Import llvm-toolchain-5.0_5.0~+rc2.orig-lld.tar.bz2
authorSylvestre Ledru <sylvestre@debian.org>
Sat, 12 Aug 2017 09:38:36 +0000 (10:38 +0100)
committerSylvestre Ledru <sylvestre@debian.org>
Sat, 12 Aug 2017 09:38:36 +0000 (10:38 +0100)
[dgit import orig llvm-toolchain-5.0_5.0~+rc2.orig-lld.tar.bz2]

1758 files changed:
.arcconfig [new file with mode: 0644]
.clang-format [new file with mode: 0644]
.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
CODE_OWNERS.TXT [new file with mode: 0644]
COFF/CMakeLists.txt [new file with mode: 0644]
COFF/Chunks.cpp [new file with mode: 0644]
COFF/Chunks.h [new file with mode: 0644]
COFF/Config.h [new file with mode: 0644]
COFF/DLL.cpp [new file with mode: 0644]
COFF/DLL.h [new file with mode: 0644]
COFF/Driver.cpp [new file with mode: 0644]
COFF/Driver.h [new file with mode: 0644]
COFF/DriverUtils.cpp [new file with mode: 0644]
COFF/Error.cpp [new file with mode: 0644]
COFF/Error.h [new file with mode: 0644]
COFF/ICF.cpp [new file with mode: 0644]
COFF/InputFiles.cpp [new file with mode: 0644]
COFF/InputFiles.h [new file with mode: 0644]
COFF/LTO.cpp [new file with mode: 0644]
COFF/LTO.h [new file with mode: 0644]
COFF/MapFile.cpp [new file with mode: 0644]
COFF/MapFile.h [new file with mode: 0644]
COFF/MarkLive.cpp [new file with mode: 0644]
COFF/Memory.h [new file with mode: 0644]
COFF/Options.td [new file with mode: 0644]
COFF/PDB.cpp [new file with mode: 0644]
COFF/PDB.h [new file with mode: 0644]
COFF/README.md [new file with mode: 0644]
COFF/Strings.cpp [new file with mode: 0644]
COFF/Strings.h [new file with mode: 0644]
COFF/SymbolTable.cpp [new file with mode: 0644]
COFF/SymbolTable.h [new file with mode: 0644]
COFF/Symbols.cpp [new file with mode: 0644]
COFF/Symbols.h [new file with mode: 0644]
COFF/Writer.cpp [new file with mode: 0644]
COFF/Writer.h [new file with mode: 0644]
ELF/Arch/AArch64.cpp [new file with mode: 0644]
ELF/Arch/AMDGPU.cpp [new file with mode: 0644]
ELF/Arch/ARM.cpp [new file with mode: 0644]
ELF/Arch/AVR.cpp [new file with mode: 0644]
ELF/Arch/Mips.cpp [new file with mode: 0644]
ELF/Arch/MipsArchTree.cpp [new file with mode: 0644]
ELF/Arch/PPC.cpp [new file with mode: 0644]
ELF/Arch/PPC64.cpp [new file with mode: 0644]
ELF/Arch/SPARCV9.cpp [new file with mode: 0644]
ELF/Arch/X86.cpp [new file with mode: 0644]
ELF/Arch/X86_64.cpp [new file with mode: 0644]
ELF/CMakeLists.txt [new file with mode: 0644]
ELF/Config.h [new file with mode: 0644]
ELF/Driver.cpp [new file with mode: 0644]
ELF/Driver.h [new file with mode: 0644]
ELF/DriverUtils.cpp [new file with mode: 0644]
ELF/EhFrame.cpp [new file with mode: 0644]
ELF/EhFrame.h [new file with mode: 0644]
ELF/Error.cpp [new file with mode: 0644]
ELF/Error.h [new file with mode: 0644]
ELF/Filesystem.cpp [new file with mode: 0644]
ELF/Filesystem.h [new file with mode: 0644]
ELF/GdbIndex.cpp [new file with mode: 0644]
ELF/GdbIndex.h [new file with mode: 0644]
ELF/ICF.cpp [new file with mode: 0644]
ELF/ICF.h [new file with mode: 0644]
ELF/InputFiles.cpp [new file with mode: 0644]
ELF/InputFiles.h [new file with mode: 0644]
ELF/InputSection.cpp [new file with mode: 0644]
ELF/InputSection.h [new file with mode: 0644]
ELF/LTO.cpp [new file with mode: 0644]
ELF/LTO.h [new file with mode: 0644]
ELF/LinkerScript.cpp [new file with mode: 0644]
ELF/LinkerScript.h [new file with mode: 0644]
ELF/MapFile.cpp [new file with mode: 0644]
ELF/MapFile.h [new file with mode: 0644]
ELF/MarkLive.cpp [new file with mode: 0644]
ELF/Memory.h [new file with mode: 0644]
ELF/Options.td [new file with mode: 0644]
ELF/OutputSections.cpp [new file with mode: 0644]
ELF/OutputSections.h [new file with mode: 0644]
ELF/README.md [new file with mode: 0644]
ELF/Relocations.cpp [new file with mode: 0644]
ELF/Relocations.h [new file with mode: 0644]
ELF/ScriptLexer.cpp [new file with mode: 0644]
ELF/ScriptLexer.h [new file with mode: 0644]
ELF/ScriptParser.cpp [new file with mode: 0644]
ELF/ScriptParser.h [new file with mode: 0644]
ELF/Strings.cpp [new file with mode: 0644]
ELF/Strings.h [new file with mode: 0644]
ELF/SymbolTable.cpp [new file with mode: 0644]
ELF/SymbolTable.h [new file with mode: 0644]
ELF/Symbols.cpp [new file with mode: 0644]
ELF/Symbols.h [new file with mode: 0644]
ELF/SyntheticSections.cpp [new file with mode: 0644]
ELF/SyntheticSections.h [new file with mode: 0644]
ELF/Target.cpp [new file with mode: 0644]
ELF/Target.h [new file with mode: 0644]
ELF/Threads.h [new file with mode: 0644]
ELF/Thunks.cpp [new file with mode: 0644]
ELF/Thunks.h [new file with mode: 0644]
ELF/Writer.cpp [new file with mode: 0644]
ELF/Writer.h [new file with mode: 0644]
LICENSE.TXT [new file with mode: 0644]
README.md [new file with mode: 0644]
cmake/modules/AddLLD.cmake [new file with mode: 0644]
cmake/modules/FindVTune.cmake [new file with mode: 0644]
docs/AtomLLD.rst [new file with mode: 0644]
docs/CMakeLists.txt [new file with mode: 0644]
docs/Driver.rst [new file with mode: 0644]
docs/NewLLD.rst [new file with mode: 0644]
docs/README.txt [new file with mode: 0644]
docs/Readers.rst [new file with mode: 0644]
docs/ReleaseNotes.rst [new file with mode: 0644]
docs/_static/favicon.ico [new file with mode: 0644]
docs/_templates/indexsidebar.html [new file with mode: 0644]
docs/_templates/layout.html [new file with mode: 0644]
docs/conf.py [new file with mode: 0644]
docs/design.rst [new file with mode: 0644]
docs/development.rst [new file with mode: 0644]
docs/getting_started.rst [new file with mode: 0644]
docs/hello.png [new file with mode: 0644]
docs/index.rst [new file with mode: 0644]
docs/llvm-theme/layout.html [new file with mode: 0644]
docs/llvm-theme/static/contents.png [new file with mode: 0644]
docs/llvm-theme/static/llvm.css [new file with mode: 0644]
docs/llvm-theme/static/logo.png [new file with mode: 0644]
docs/llvm-theme/static/navigation.png [new file with mode: 0644]
docs/llvm-theme/theme.conf [new file with mode: 0644]
docs/make.bat [new file with mode: 0644]
docs/open_projects.rst [new file with mode: 0644]
docs/sphinx_intro.rst [new file with mode: 0644]
docs/windows_support.rst [new file with mode: 0644]
include/lld/Config/Version.h [new file with mode: 0644]
include/lld/Config/Version.inc.in [new file with mode: 0644]
include/lld/Core/AbsoluteAtom.h [new file with mode: 0644]
include/lld/Core/ArchiveLibraryFile.h [new file with mode: 0644]
include/lld/Core/Atom.h [new file with mode: 0644]
include/lld/Core/DefinedAtom.h [new file with mode: 0644]
include/lld/Core/Error.h [new file with mode: 0644]
include/lld/Core/File.h [new file with mode: 0644]
include/lld/Core/Instrumentation.h [new file with mode: 0644]
include/lld/Core/LLVM.h [new file with mode: 0644]
include/lld/Core/LinkingContext.h [new file with mode: 0644]
include/lld/Core/Node.h [new file with mode: 0644]
include/lld/Core/Pass.h [new file with mode: 0644]
include/lld/Core/PassManager.h [new file with mode: 0644]
include/lld/Core/Reader.h [new file with mode: 0644]
include/lld/Core/Reference.h [new file with mode: 0644]
include/lld/Core/Reproduce.h [new file with mode: 0644]
include/lld/Core/Resolver.h [new file with mode: 0644]
include/lld/Core/SharedLibraryAtom.h [new file with mode: 0644]
include/lld/Core/SharedLibraryFile.h [new file with mode: 0644]
include/lld/Core/Simple.h [new file with mode: 0644]
include/lld/Core/SymbolTable.h [new file with mode: 0644]
include/lld/Core/TODO.txt [new file with mode: 0644]
include/lld/Core/TargetOptionsCommandFlags.h [new file with mode: 0644]
include/lld/Core/UndefinedAtom.h [new file with mode: 0644]
include/lld/Core/Writer.h [new file with mode: 0644]
include/lld/Driver/Driver.h [new file with mode: 0644]
include/lld/ReaderWriter/MachOLinkingContext.h [new file with mode: 0644]
include/lld/ReaderWriter/YamlContext.h [new file with mode: 0644]
lib/CMakeLists.txt [new file with mode: 0644]
lib/Config/CMakeLists.txt [new file with mode: 0644]
lib/Config/Version.cpp [new file with mode: 0644]
lib/Core/CMakeLists.txt [new file with mode: 0644]
lib/Core/DefinedAtom.cpp [new file with mode: 0644]
lib/Core/Error.cpp [new file with mode: 0644]
lib/Core/File.cpp [new file with mode: 0644]
lib/Core/LinkingContext.cpp [new file with mode: 0644]
lib/Core/Reader.cpp [new file with mode: 0644]
lib/Core/Reproduce.cpp [new file with mode: 0644]
lib/Core/Resolver.cpp [new file with mode: 0644]
lib/Core/SymbolTable.cpp [new file with mode: 0644]
lib/Core/TargetOptionsCommandFlags.cpp [new file with mode: 0644]
lib/Core/Writer.cpp [new file with mode: 0644]
lib/Driver/CMakeLists.txt [new file with mode: 0644]
lib/Driver/DarwinLdDriver.cpp [new file with mode: 0644]
lib/Driver/DarwinLdOptions.td [new file with mode: 0644]
lib/ReaderWriter/CMakeLists.txt [new file with mode: 0644]
lib/ReaderWriter/FileArchive.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler.h [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_arm.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_arm64.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_x86.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/Atoms.h [new file with mode: 0644]
lib/ReaderWriter/MachO/CMakeLists.txt [new file with mode: 0644]
lib/ReaderWriter/MachO/CompactUnwindPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/DebugInfo.h [new file with mode: 0644]
lib/ReaderWriter/MachO/ExecutableAtoms.h [new file with mode: 0644]
lib/ReaderWriter/MachO/File.h [new file with mode: 0644]
lib/ReaderWriter/MachO/FlatNamespaceFile.h [new file with mode: 0644]
lib/ReaderWriter/MachO/GOTPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/LayoutPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/LayoutPass.h [new file with mode: 0644]
lib/ReaderWriter/MachO/MachOLinkingContext.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFile.h [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/MachOPasses.h [new file with mode: 0644]
lib/ReaderWriter/MachO/ObjCPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/SectCreateFile.h [new file with mode: 0644]
lib/ReaderWriter/MachO/ShimPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/StubsPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/TLVPass.cpp [new file with mode: 0644]
lib/ReaderWriter/MachO/WriterMachO.cpp [new file with mode: 0644]
lib/ReaderWriter/YAML/CMakeLists.txt [new file with mode: 0644]
lib/ReaderWriter/YAML/ReaderWriterYAML.cpp [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/COFF/Inputs/armnt-executable.obj.yaml [new file with mode: 0644]
test/COFF/Inputs/armnt-executable.s [new file with mode: 0644]
test/COFF/Inputs/associative-comdat-2.s [new file with mode: 0644]
test/COFF/Inputs/bar.ll [new file with mode: 0644]
test/COFF/Inputs/cl-gl.obj [new file with mode: 0755]
test/COFF/Inputs/combined-resources-2.rc [new file with mode: 0644]
test/COFF/Inputs/combined-resources-2.res [new file with mode: 0644]
test/COFF/Inputs/combined-resources-cursor.bmp [new file with mode: 0644]
test/COFF/Inputs/combined-resources-okay.bmp [new file with mode: 0644]
test/COFF/Inputs/combined-resources.rc [new file with mode: 0644]
test/COFF/Inputs/combined-resources.res [new file with mode: 0644]
test/COFF/Inputs/conflict.ll [new file with mode: 0644]
test/COFF/Inputs/constant-export.ll [new file with mode: 0644]
test/COFF/Inputs/constant-import.s [new file with mode: 0644]
test/COFF/Inputs/default.def [new file with mode: 0644]
test/COFF/Inputs/delayimports-error.yaml [new file with mode: 0644]
test/COFF/Inputs/entry-mangled.ll [new file with mode: 0644]
test/COFF/Inputs/export.ll [new file with mode: 0644]
test/COFF/Inputs/export.yaml [new file with mode: 0644]
test/COFF/Inputs/export2.yaml [new file with mode: 0644]
test/COFF/Inputs/extension.def [new file with mode: 0644]
test/COFF/Inputs/far-arm-thumb-abs.s [new file with mode: 0644]
test/COFF/Inputs/hello32.yaml [new file with mode: 0644]
test/COFF/Inputs/hello64.asm [new file with mode: 0644]
test/COFF/Inputs/hello64.obj [new file with mode: 0644]
test/COFF/Inputs/import.yaml [new file with mode: 0644]
test/COFF/Inputs/imports-mangle.lib [new file with mode: 0644]
test/COFF/Inputs/include1a.yaml [new file with mode: 0644]
test/COFF/Inputs/include1b.yaml [new file with mode: 0644]
test/COFF/Inputs/include1c.yaml [new file with mode: 0644]
test/COFF/Inputs/library-arm64.lib [new file with mode: 0644]
test/COFF/Inputs/library.def [new file with mode: 0644]
test/COFF/Inputs/library.lib [new file with mode: 0755]
test/COFF/Inputs/lto-chkstk-chkstk.s [new file with mode: 0644]
test/COFF/Inputs/lto-chkstk-foo.s [new file with mode: 0644]
test/COFF/Inputs/lto-comdat1.ll [new file with mode: 0644]
test/COFF/Inputs/lto-comdat2.ll [new file with mode: 0644]
test/COFF/Inputs/lto-dep.ll [new file with mode: 0644]
test/COFF/Inputs/lto-lazy-reference-dummy.ll [new file with mode: 0644]
test/COFF/Inputs/lto-lazy-reference-quadruple.ll [new file with mode: 0644]
test/COFF/Inputs/machine-x64.yaml [new file with mode: 0644]
test/COFF/Inputs/machine-x86.yaml [new file with mode: 0644]
test/COFF/Inputs/manifestinput.test [new file with mode: 0644]
test/COFF/Inputs/msvclto-order-a.ll [new file with mode: 0644]
test/COFF/Inputs/msvclto-order-b.ll [new file with mode: 0644]
test/COFF/Inputs/msvclto.s [new file with mode: 0644]
test/COFF/Inputs/named.def [new file with mode: 0644]
test/COFF/Inputs/object.s [new file with mode: 0644]
test/COFF/Inputs/oldname.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb-diff-cl.pdb [new file with mode: 0644]
test/COFF/Inputs/pdb-diff.cpp [new file with mode: 0644]
test/COFF/Inputs/pdb-diff.obj [new file with mode: 0644]
test/COFF/Inputs/pdb-global-gc.s [new file with mode: 0644]
test/COFF/Inputs/pdb-import-gc.lib [new file with mode: 0644]
test/COFF/Inputs/pdb-scopes-a.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb-scopes-b.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb-type-server-simple-a.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb-type-server-simple-b.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb-type-server-simple-ts.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb1.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb2.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb_comdat_bar.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb_comdat_main.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb_lines_1.yaml [new file with mode: 0644]
test/COFF/Inputs/pdb_lines_2.yaml [new file with mode: 0644]
test/COFF/Inputs/resource.res [new file with mode: 0644]
test/COFF/Inputs/ret42.lib [new file with mode: 0644]
test/COFF/Inputs/ret42.obj [new file with mode: 0644]
test/COFF/Inputs/ret42.yaml [new file with mode: 0644]
test/COFF/Inputs/std32.lib [new file with mode: 0644]
test/COFF/Inputs/std64.lib [new file with mode: 0644]
test/COFF/Inputs/thinlto-mangled-qux.ll [new file with mode: 0644]
test/COFF/Inputs/weak-external.ll [new file with mode: 0644]
test/COFF/Inputs/weak-external2.ll [new file with mode: 0644]
test/COFF/Inputs/weak-external3.ll [new file with mode: 0644]
test/COFF/alternatename.test [new file with mode: 0644]
test/COFF/ar-comdat.test [new file with mode: 0644]
test/COFF/arm-thumb-branch-error.s [new file with mode: 0644]
test/COFF/arm64-magic.yaml [new file with mode: 0644]
test/COFF/arm64-relocs-imports.test [new file with mode: 0644]
test/COFF/armnt-blx23t.test [new file with mode: 0644]
test/COFF/armnt-branch24t.test [new file with mode: 0644]
test/COFF/armnt-entry-point.test [new file with mode: 0644]
test/COFF/armnt-imports.test [new file with mode: 0644]
test/COFF/armnt-mov32t-exec.test [new file with mode: 0644]
test/COFF/armnt-movt32t.test [new file with mode: 0644]
test/COFF/associative-comdat.s [new file with mode: 0644]
test/COFF/base.test [new file with mode: 0644]
test/COFF/baserel.test [new file with mode: 0644]
test/COFF/cl-gl.test [new file with mode: 0644]
test/COFF/combined-resources.test [new file with mode: 0644]
test/COFF/common.test [new file with mode: 0644]
test/COFF/conflict-mangled.test [new file with mode: 0644]
test/COFF/conflict.test [new file with mode: 0644]
test/COFF/constant-export.test [new file with mode: 0644]
test/COFF/constant.test [new file with mode: 0644]
test/COFF/debug.test [new file with mode: 0644]
test/COFF/def-export-stdcall.s [new file with mode: 0644]
test/COFF/def-name.test [new file with mode: 0644]
test/COFF/defparser.test [new file with mode: 0644]
test/COFF/delayimports-error.test [new file with mode: 0644]
test/COFF/delayimports.test [new file with mode: 0644]
test/COFF/delayimports32.test [new file with mode: 0644]
test/COFF/dll.test [new file with mode: 0644]
test/COFF/dllimport-gc.test [new file with mode: 0644]
test/COFF/driver-windows.test [new file with mode: 0644]
test/COFF/driver.test [new file with mode: 0644]
test/COFF/entry-inference.test [new file with mode: 0644]
test/COFF/entry-inference2.test [new file with mode: 0644]
test/COFF/entry-inference32.test [new file with mode: 0644]
test/COFF/entry-mangled.test [new file with mode: 0644]
test/COFF/entrylib.ll [new file with mode: 0644]
test/COFF/error-limit.test [new file with mode: 0644]
test/COFF/export-exe.test [new file with mode: 0644]
test/COFF/export.test [new file with mode: 0644]
test/COFF/export32.test [new file with mode: 0644]
test/COFF/failifmismatch.test [new file with mode: 0644]
test/COFF/filetype.test [new file with mode: 0644]
test/COFF/force.test [new file with mode: 0644]
test/COFF/guardcf.test [new file with mode: 0644]
test/COFF/heap.test [new file with mode: 0644]
test/COFF/hello32.test [new file with mode: 0644]
test/COFF/help.test [new file with mode: 0644]
test/COFF/icf-associative.test [new file with mode: 0644]
test/COFF/icf-circular.test [new file with mode: 0644]
test/COFF/icf-circular2.test [new file with mode: 0644]
test/COFF/icf-data.test [new file with mode: 0644]
test/COFF/icf-different-align.test [new file with mode: 0644]
test/COFF/icf-local.test [new file with mode: 0644]
test/COFF/icf-simple.test [new file with mode: 0644]
test/COFF/implib-name.test [new file with mode: 0644]
test/COFF/imports-mangle.test [new file with mode: 0644]
test/COFF/imports.test [new file with mode: 0644]
test/COFF/include-lto.ll [new file with mode: 0644]
test/COFF/include.test [new file with mode: 0644]
test/COFF/include2.test [new file with mode: 0644]
test/COFF/internal.test [new file with mode: 0644]
test/COFF/invalid-debug-type.test [new file with mode: 0644]
test/COFF/invalid-obj.test [new file with mode: 0644]
test/COFF/largeaddressaware.test [new file with mode: 0644]
test/COFF/lib.test [new file with mode: 0644]
test/COFF/libpath.test [new file with mode: 0644]
test/COFF/linkenv.test [new file with mode: 0644]
test/COFF/linkrepro.test [new file with mode: 0644]
test/COFF/lldmap.test [new file with mode: 0644]
test/COFF/loadcfg.ll [new file with mode: 0644]
test/COFF/loadcfg.test [new file with mode: 0644]
test/COFF/loadcfg32.test [new file with mode: 0644]
test/COFF/locally-imported.test [new file with mode: 0644]
test/COFF/locally-imported32.test [new file with mode: 0644]
test/COFF/long-section-name.test [new file with mode: 0644]
test/COFF/lto-chkstk.ll [new file with mode: 0644]
test/COFF/lto-comdat.ll [new file with mode: 0644]
test/COFF/lto-debug-pass-arguments.ll [new file with mode: 0644]
test/COFF/lto-lazy-reference.ll [new file with mode: 0644]
test/COFF/lto-linker-opts.ll [new file with mode: 0644]
test/COFF/lto-new-symbol.ll [new file with mode: 0644]
test/COFF/lto-opt-level.ll [new file with mode: 0644]
test/COFF/lto-parallel.ll [new file with mode: 0644]
test/COFF/lto.ll [new file with mode: 0644]
test/COFF/machine.test [new file with mode: 0644]
test/COFF/manifest.test [new file with mode: 0644]
test/COFF/manifestinput.test [new file with mode: 0644]
test/COFF/merge.test [new file with mode: 0644]
test/COFF/msvclto-archive.ll [new file with mode: 0644]
test/COFF/msvclto-order.ll [new file with mode: 0644]
test/COFF/msvclto.ll [new file with mode: 0644]
test/COFF/nodefaultlib.test [new file with mode: 0644]
test/COFF/noentry.test [new file with mode: 0644]
test/COFF/nopdb.test [new file with mode: 0644]
test/COFF/opt.test [new file with mode: 0644]
test/COFF/options.test [new file with mode: 0644]
test/COFF/order.test [new file with mode: 0644]
test/COFF/out.test [new file with mode: 0644]
test/COFF/pdb-comdat.test [new file with mode: 0644]
test/COFF/pdb-diff.test [new file with mode: 0644]
test/COFF/pdb-global-gc.yaml [new file with mode: 0644]
test/COFF/pdb-import-gc.yaml [new file with mode: 0644]
test/COFF/pdb-invalid-func-type.yaml [new file with mode: 0644]
test/COFF/pdb-lib.s [new file with mode: 0644]
test/COFF/pdb-linker-module.test [new file with mode: 0644]
test/COFF/pdb-none.test [new file with mode: 0644]
test/COFF/pdb-options.test [new file with mode: 0644]
test/COFF/pdb-safeseh.yaml [new file with mode: 0644]
test/COFF/pdb-scopes.test [new file with mode: 0644]
test/COFF/pdb-secrel-absolute.yaml [new file with mode: 0644]
test/COFF/pdb-source-lines.test [new file with mode: 0644]
test/COFF/pdb-symbol-types.yaml [new file with mode: 0644]
test/COFF/pdb-type-server-missing.yaml [new file with mode: 0644]
test/COFF/pdb-type-server-simple.test [new file with mode: 0644]
test/COFF/pdb.test [new file with mode: 0644]
test/COFF/reloc-arm.test [new file with mode: 0644]
test/COFF/reloc-discarded-dwarf.s [new file with mode: 0644]
test/COFF/reloc-discarded.s [new file with mode: 0644]
test/COFF/reloc-oob.yaml [new file with mode: 0644]
test/COFF/reloc-x64.test [new file with mode: 0644]
test/COFF/reloc-x86.test [new file with mode: 0644]
test/COFF/resource.test [new file with mode: 0644]
test/COFF/responsefile.test [new file with mode: 0644]
test/COFF/rsds.test [new file with mode: 0644]
test/COFF/safeseh-diag-feat.test [new file with mode: 0644]
test/COFF/safeseh.s [new file with mode: 0644]
test/COFF/savetemps.ll [new file with mode: 0644]
test/COFF/secidx-absolute.s [new file with mode: 0644]
test/COFF/secrel-absolute.s [new file with mode: 0644]
test/COFF/secrel-common.s [new file with mode: 0644]
test/COFF/section.test [new file with mode: 0644]
test/COFF/seh.test [new file with mode: 0644]
test/COFF/sort-debug.test [new file with mode: 0644]
test/COFF/stack.test [new file with mode: 0644]
test/COFF/subsystem-inference.test [new file with mode: 0644]
test/COFF/subsystem.test [new file with mode: 0644]
test/COFF/symtab.test [new file with mode: 0644]
test/COFF/thinlto-archives.ll [new file with mode: 0644]
test/COFF/thinlto-mangled.ll [new file with mode: 0644]
test/COFF/thinlto.ll [new file with mode: 0644]
test/COFF/tls.test [new file with mode: 0644]
test/COFF/tls32.test [new file with mode: 0644]
test/COFF/unwind.test [new file with mode: 0644]
test/COFF/version.test [new file with mode: 0644]
test/COFF/weak-external.test [new file with mode: 0644]
test/COFF/weak-external2.test [new file with mode: 0644]
test/COFF/weak-external3.test [new file with mode: 0644]
test/Driver/Inputs/libtest.a [new file with mode: 0644]
test/Driver/Inputs/usr/lib/i386/libtest.a [new file with mode: 0644]
test/Driver/Inputs/usr/lib/libtest.a [new file with mode: 0644]
test/ELF/Inputs/aarch64-condb-reloc.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-copy2.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-tls-gdie.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-tls-ie.s [new file with mode: 0644]
test/ELF/Inputs/aarch64-tstbr14-reloc.s [new file with mode: 0644]
test/ELF/Inputs/abs-hidden.s [new file with mode: 0644]
test/ELF/Inputs/abs.s [new file with mode: 0644]
test/ELF/Inputs/abs255.s [new file with mode: 0644]
test/ELF/Inputs/abs256.s [new file with mode: 0644]
test/ELF/Inputs/abs257.s [new file with mode: 0644]
test/ELF/Inputs/allow-multiple-definition.s [new file with mode: 0644]
test/ELF/Inputs/allow-shlib-undefined.s [new file with mode: 0644]
test/ELF/Inputs/archive.s [new file with mode: 0644]
test/ELF/Inputs/archive2.s [new file with mode: 0644]
test/ELF/Inputs/archive3.s [new file with mode: 0644]
test/ELF/Inputs/archive4.s [new file with mode: 0644]
test/ELF/Inputs/arm-attributes1.s [new file with mode: 0644]
test/ELF/Inputs/arm-exidx-cantunwind.s [new file with mode: 0644]
test/ELF/Inputs/arm-plt-reloc.s [new file with mode: 0644]
test/ELF/Inputs/arm-shared.s [new file with mode: 0644]
test/ELF/Inputs/arm-thumb-blx-targets.s [new file with mode: 0644]
test/ELF/Inputs/arm-thumb-narrow-branch.o [new file with mode: 0644]
test/ELF/Inputs/arm-thumb-narrow-branch.s [new file with mode: 0644]
test/ELF/Inputs/arm-tls-get-addr.s [new file with mode: 0644]
test/ELF/Inputs/bad-archive.a [new file with mode: 0644]
test/ELF/Inputs/comdat.s [new file with mode: 0644]
test/ELF/Inputs/comment-gc.s [new file with mode: 0644]
test/ELF/Inputs/common.s [new file with mode: 0644]
test/ELF/Inputs/conflict-debug.s [new file with mode: 0644]
test/ELF/Inputs/conflict.s [new file with mode: 0644]
test/ELF/Inputs/copy-in-shared.s [new file with mode: 0644]
test/ELF/Inputs/copy-rel-corrupted.s [new file with mode: 0644]
test/ELF/Inputs/copy-rel-pie.s [new file with mode: 0644]
test/ELF/Inputs/ctors_dtors_priority1.s [new file with mode: 0644]
test/ELF/Inputs/ctors_dtors_priority2.s [new file with mode: 0644]
test/ELF/Inputs/ctors_dtors_priority3.s [new file with mode: 0644]
test/ELF/Inputs/discard-merge-unnamed.o [new file with mode: 0644]
test/ELF/Inputs/dso-undef-size.s [new file with mode: 0644]
test/ELF/Inputs/dtrace-r.o [new file with mode: 0644]
test/ELF/Inputs/duplicated-plt-entry.s [new file with mode: 0644]
test/ELF/Inputs/dynamic-reloc-weak.s [new file with mode: 0644]
test/ELF/Inputs/dynamic-reloc.s [new file with mode: 0644]
test/ELF/Inputs/eh-frame-end.s [new file with mode: 0644]
test/ELF/Inputs/ehframe-relocation.s [new file with mode: 0644]
test/ELF/Inputs/empty-ver.ver [new file with mode: 0644]
test/ELF/Inputs/exclude-libs.s [new file with mode: 0644]
test/ELF/Inputs/far-arm-abs.s [new file with mode: 0644]
test/ELF/Inputs/far-arm-thumb-abs.s [new file with mode: 0644]
test/ELF/Inputs/gc-sections-weak.s [new file with mode: 0644]
test/ELF/Inputs/gdb-index.s [new file with mode: 0644]
test/ELF/Inputs/gnu-ifunc-dso.s [new file with mode: 0644]
test/ELF/Inputs/gnu-ifunc-gotpcrel.s [new file with mode: 0644]
test/ELF/Inputs/gotpc-relax-und-dso.s [new file with mode: 0644]
test/ELF/Inputs/i386-got32x-baseless.elf [new file with mode: 0644]
test/ELF/Inputs/i386-reloc-16-error.s [new file with mode: 0644]
test/ELF/Inputs/i386-reloc-16.s [new file with mode: 0644]
test/ELF/Inputs/i386-reloc-8-error.s [new file with mode: 0644]
test/ELF/Inputs/i386-reloc-8.s [new file with mode: 0644]
test/ELF/Inputs/i386-tls-got.s [new file with mode: 0644]
test/ELF/Inputs/icf-absolute.s [new file with mode: 0644]
test/ELF/Inputs/icf-merge-sec.s [new file with mode: 0644]
test/ELF/Inputs/icf-merge.s [new file with mode: 0644]
test/ELF/Inputs/icf-merge2.s [new file with mode: 0644]
test/ELF/Inputs/icf-merge3.s [new file with mode: 0644]
test/ELF/Inputs/icf-non-mergeable.s [new file with mode: 0644]
test/ELF/Inputs/icf2.s [new file with mode: 0644]
test/ELF/Inputs/libsearch-dyn.s [new file with mode: 0644]
test/ELF/Inputs/libsearch-st.s [new file with mode: 0644]
test/ELF/Inputs/llvm33-rela-outside-group.o [new file with mode: 0644]
test/ELF/Inputs/map-file2.s [new file with mode: 0644]
test/ELF/Inputs/map-file3.s [new file with mode: 0644]
test/ELF/Inputs/map-file4.s [new file with mode: 0644]
test/ELF/Inputs/merge.s [new file with mode: 0644]
test/ELF/Inputs/mips-align-err.s [new file with mode: 0644]
test/ELF/Inputs/mips-concatenated-abiflags.o [new file with mode: 0644]
test/ELF/Inputs/mips-dynamic.s [new file with mode: 0644]
test/ELF/Inputs/mips-fnpic.s [new file with mode: 0644]
test/ELF/Inputs/mips-fpic.s [new file with mode: 0644]
test/ELF/Inputs/mips-gp-disp.so [new file with mode: 0644]
test/ELF/Inputs/mips-gp0-non-zero.o [new file with mode: 0755]
test/ELF/Inputs/mips-n32-rels.o [new file with mode: 0644]
test/ELF/Inputs/mips-nonalloc.s [new file with mode: 0644]
test/ELF/Inputs/mips-options.o [new file with mode: 0644]
test/ELF/Inputs/mips-pic.s [new file with mode: 0644]
test/ELF/Inputs/mips-tls.s [new file with mode: 0644]
test/ELF/Inputs/no-symtab.o [new file with mode: 0644]
test/ELF/Inputs/plt-aarch64.s [new file with mode: 0644]
test/ELF/Inputs/ppc64-addr16-error.s [new file with mode: 0644]
test/ELF/Inputs/progname-ver.s [new file with mode: 0644]
test/ELF/Inputs/protected-shared.s [new file with mode: 0644]
test/ELF/Inputs/relocatable-comdat-multiple.s [new file with mode: 0644]
test/ELF/Inputs/relocatable-ehframe.s [new file with mode: 0644]
test/ELF/Inputs/relocatable-non-alloc.s [new file with mode: 0644]
test/ELF/Inputs/relocatable-tls.s [new file with mode: 0644]
test/ELF/Inputs/relocatable.s [new file with mode: 0644]
test/ELF/Inputs/relocatable2.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-alias.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-align-common.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-align.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-arm.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy-relro.s [new file with mode: 0644]
test/ELF/Inputs/relocation-copy.s [new file with mode: 0644]
test/ELF/Inputs/relocation-relative-absolute.s [new file with mode: 0644]
test/ELF/Inputs/relocation-size-shared.s [new file with mode: 0644]
test/ELF/Inputs/resolution-end.s [new file with mode: 0644]
test/ELF/Inputs/resolution-shared.s [new file with mode: 0644]
test/ELF/Inputs/resolution.s [new file with mode: 0644]
test/ELF/Inputs/rodynamic.s [new file with mode: 0644]
test/ELF/Inputs/shared-ppc64.s [new file with mode: 0644]
test/ELF/Inputs/shared.s [new file with mode: 0644]
test/ELF/Inputs/shared2-x86-64.s [new file with mode: 0644]
test/ELF/Inputs/shared2.s [new file with mode: 0644]
test/ELF/Inputs/shared3.s [new file with mode: 0644]
test/ELF/Inputs/shf-info-link.test [new file with mode: 0644]
test/ELF/Inputs/sht-group-gold-r.elf [new file with mode: 0644]
test/ELF/Inputs/sht-group-gold-r.s [new file with mode: 0644]
test/ELF/Inputs/start-lib-comdat.s [new file with mode: 0644]
test/ELF/Inputs/start-lib1.s [new file with mode: 0644]
test/ELF/Inputs/start-lib2.s [new file with mode: 0644]
test/ELF/Inputs/startstop-shared2.s [new file with mode: 0644]
test/ELF/Inputs/symbol-override.s [new file with mode: 0644]
test/ELF/Inputs/symver-archive1.s [new file with mode: 0644]
test/ELF/Inputs/symver-archive2.s [new file with mode: 0644]
test/ELF/Inputs/tls-got-entry.s [new file with mode: 0644]
test/ELF/Inputs/tls-got.s [new file with mode: 0644]
test/ELF/Inputs/tls-in-archive.s [new file with mode: 0644]
test/ELF/Inputs/tls-mismatch.s [new file with mode: 0644]
test/ELF/Inputs/tls-opt-gdie.s [new file with mode: 0644]
test/ELF/Inputs/tls-opt-gdiele-i686.s [new file with mode: 0644]
test/ELF/Inputs/tls-opt-iele-i686-nopic.s [new file with mode: 0644]
test/ELF/Inputs/trace-ar1.s [new file with mode: 0644]
test/ELF/Inputs/trace-ar2.s [new file with mode: 0644]
test/ELF/Inputs/trace-symbols-foo-strong.s [new file with mode: 0644]
test/ELF/Inputs/trace-symbols-foo-weak.s [new file with mode: 0644]
test/ELF/Inputs/uabs_label.s [new file with mode: 0644]
test/ELF/Inputs/undef-debug.s [new file with mode: 0644]
test/ELF/Inputs/undef-with-plt-addr.s [new file with mode: 0644]
test/ELF/Inputs/undef.s [new file with mode: 0644]
test/ELF/Inputs/unknown-reloc.s [new file with mode: 0644]
test/ELF/Inputs/unresolved-symbols.s [new file with mode: 0644]
test/ELF/Inputs/use-bar.s [new file with mode: 0644]
test/ELF/Inputs/verdef-defaultver.s [new file with mode: 0644]
test/ELF/Inputs/verdef.s [new file with mode: 0644]
test/ELF/Inputs/verneed.so.sh [new file with mode: 0755]
test/ELF/Inputs/verneed1.so [new file with mode: 0755]
test/ELF/Inputs/verneed2.so [new file with mode: 0755]
test/ELF/Inputs/version-script-err.script [new file with mode: 0644]
test/ELF/Inputs/version-script-no-warn2.s [new file with mode: 0644]
test/ELF/Inputs/version-script-weak.s [new file with mode: 0644]
test/ELF/Inputs/version-undef-sym.so [new file with mode: 0755]
test/ELF/Inputs/version-use.script [new file with mode: 0644]
test/ELF/Inputs/version-use.so [new file with mode: 0755]
test/ELF/Inputs/visibility.s [new file with mode: 0644]
test/ELF/Inputs/warn-common.s [new file with mode: 0644]
test/ELF/Inputs/warn-common2.s [new file with mode: 0644]
test/ELF/Inputs/weak-and-strong-undef.s [new file with mode: 0644]
test/ELF/Inputs/whole-archive.s [new file with mode: 0644]
test/ELF/Inputs/wrap-dynamic-undef.s [new file with mode: 0644]
test/ELF/Inputs/wrap.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-relax-offset.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-reloc-16-error.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-reloc-16.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-reloc-8-error.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-reloc-8.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-reloc-error.s [new file with mode: 0644]
test/ELF/Inputs/x86-64-tls-gd-got.s [new file with mode: 0644]
test/ELF/Inputs/ztext-text-notext.s [new file with mode: 0644]
test/ELF/aarch64-abs16.s [new file with mode: 0644]
test/ELF/aarch64-abs32.s [new file with mode: 0644]
test/ELF/aarch64-abs64-dyn.s [new file with mode: 0644]
test/ELF/aarch64-call26-error.s [new file with mode: 0644]
test/ELF/aarch64-condb-reloc.s [new file with mode: 0644]
test/ELF/aarch64-copy.s [new file with mode: 0644]
test/ELF/aarch64-copy2.s [new file with mode: 0644]
test/ELF/aarch64-data-relocs.s [new file with mode: 0644]
test/ELF/aarch64-fpic-abs16.s [new file with mode: 0644]
test/ELF/aarch64-fpic-add_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-adr_prel_lo21.s [new file with mode: 0644]
test/ELF/aarch64-fpic-adr_prel_pg_hi21.s [new file with mode: 0644]
test/ELF/aarch64-fpic-got.s [new file with mode: 0644]
test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s [new file with mode: 0644]
test/ELF/aarch64-fpic-prel16.s [new file with mode: 0644]
test/ELF/aarch64-fpic-prel32.s [new file with mode: 0644]
test/ELF/aarch64-fpic-prel64.s [new file with mode: 0644]
test/ELF/aarch64-gnu-ifunc-nosym.s [new file with mode: 0644]
test/ELF/aarch64-gnu-ifunc-plt.s [new file with mode: 0644]
test/ELF/aarch64-gnu-ifunc.s [new file with mode: 0644]
test/ELF/aarch64-got-reloc.s [new file with mode: 0644]
test/ELF/aarch64-got-relocations.s [new file with mode: 0644]
test/ELF/aarch64-got.s [new file with mode: 0644]
test/ELF/aarch64-hi21-error.s [new file with mode: 0644]
test/ELF/aarch64-jump26-error.s [new file with mode: 0644]
test/ELF/aarch64-lo21-error.s [new file with mode: 0644]
test/ELF/aarch64-prel16.s [new file with mode: 0644]
test/ELF/aarch64-prel32.s [new file with mode: 0644]
test/ELF/aarch64-relative.s [new file with mode: 0644]
test/ELF/aarch64-relocs.s [new file with mode: 0644]
test/ELF/aarch64-relro.s [new file with mode: 0644]
test/ELF/aarch64-tls-gdie.s [new file with mode: 0644]
test/ELF/aarch64-tls-gdle.s [new file with mode: 0644]
test/ELF/aarch64-tls-ie.s [new file with mode: 0644]
test/ELF/aarch64-tls-iele.s [new file with mode: 0644]
test/ELF/aarch64-tls-le.s [new file with mode: 0644]
test/ELF/aarch64-tls-pie.s [new file with mode: 0644]
test/ELF/aarch64-tls-static.s [new file with mode: 0644]
test/ELF/aarch64-tlsdesc.s [new file with mode: 0644]
test/ELF/aarch64-tstbr14-reloc.s [new file with mode: 0644]
test/ELF/aarch64-undefined-weak.s [new file with mode: 0644]
test/ELF/abs-conflict.s [new file with mode: 0644]
test/ELF/abs-hidden.s [new file with mode: 0644]
test/ELF/allow-multiple-definition.s [new file with mode: 0644]
test/ELF/allow-shlib-undefined.s [new file with mode: 0644]
test/ELF/amdgpu-globals.s [new file with mode: 0644]
test/ELF/amdgpu-kernels.s [new file with mode: 0644]
test/ELF/amdgpu-relocs.s [new file with mode: 0644]
test/ELF/archive.s [new file with mode: 0644]
test/ELF/arm-abs32-dyn.s [new file with mode: 0644]
test/ELF/arm-attributes.s [new file with mode: 0644]
test/ELF/arm-blx.s [new file with mode: 0644]
test/ELF/arm-branch-error.s [new file with mode: 0644]
test/ELF/arm-branch.s [new file with mode: 0644]
test/ELF/arm-copy.s [new file with mode: 0644]
test/ELF/arm-data-prel.s [new file with mode: 0644]
test/ELF/arm-data-relocs.s [new file with mode: 0644]
test/ELF/arm-eabi-version.s [new file with mode: 0644]
test/ELF/arm-exidx-canunwind.s [new file with mode: 0644]
test/ELF/arm-exidx-gc.s [new file with mode: 0644]
test/ELF/arm-exidx-link.s [new file with mode: 0644]
test/ELF/arm-exidx-order.s [new file with mode: 0644]
test/ELF/arm-exidx-output.s [new file with mode: 0644]
test/ELF/arm-exidx-relocatable.s [new file with mode: 0644]
test/ELF/arm-exidx-sentinel-norelocatable.s [new file with mode: 0644]
test/ELF/arm-exidx-sentinel-orphan.s [new file with mode: 0644]
test/ELF/arm-exidx-shared.s [new file with mode: 0644]
test/ELF/arm-fpic-got.s [new file with mode: 0644]
test/ELF/arm-gnu-ifunc-nosym.s [new file with mode: 0644]
test/ELF/arm-gnu-ifunc-plt.s [new file with mode: 0644]
test/ELF/arm-gnu-ifunc.s [new file with mode: 0644]
test/ELF/arm-got-relative.s [new file with mode: 0644]
test/ELF/arm-gotoff.s [new file with mode: 0644]
test/ELF/arm-icf-exidx.s [new file with mode: 0644]
test/ELF/arm-mov-relocs.s [new file with mode: 0644]
test/ELF/arm-pie-relative.s [new file with mode: 0644]
test/ELF/arm-plt-reloc.s [new file with mode: 0644]
test/ELF/arm-sbrel32.s [new file with mode: 0644]
test/ELF/arm-static-defines.s [new file with mode: 0644]
test/ELF/arm-target1.s [new file with mode: 0644]
test/ELF/arm-target2.s [new file with mode: 0644]
test/ELF/arm-thumb-blx.s [new file with mode: 0644]
test/ELF/arm-thumb-branch-error.s [new file with mode: 0644]
test/ELF/arm-thumb-branch.s [new file with mode: 0644]
test/ELF/arm-thumb-interwork-shared.s [new file with mode: 0644]
test/ELF/arm-thumb-interwork-thunk-range.s [new file with mode: 0644]
test/ELF/arm-thumb-interwork-thunk.s [new file with mode: 0644]
test/ELF/arm-thumb-narrow-branch-check.s [new file with mode: 0644]
test/ELF/arm-thumb-no-undefined-thunk.s [new file with mode: 0644]
test/ELF/arm-thumb-plt-reloc.s [new file with mode: 0644]
test/ELF/arm-thumb-thunk-symbols.s [new file with mode: 0644]
test/ELF/arm-thumb-undefined-weak.s [new file with mode: 0644]
test/ELF/arm-tls-gd-nonpreemptible.s [new file with mode: 0644]
test/ELF/arm-tls-gd32.s [new file with mode: 0644]
test/ELF/arm-tls-ie32.s [new file with mode: 0644]
test/ELF/arm-tls-ldm32.s [new file with mode: 0644]
test/ELF/arm-tls-le32.s [new file with mode: 0644]
test/ELF/arm-tls-norelax-gd-ie.s [new file with mode: 0644]
test/ELF/arm-tls-norelax-gd-le.s [new file with mode: 0644]
test/ELF/arm-tls-norelax-ie-le.s [new file with mode: 0644]
test/ELF/arm-tls-norelax-ld-le.s [new file with mode: 0644]
test/ELF/arm-undefined-weak.s [new file with mode: 0644]
test/ELF/arm-use-r-output.s [new file with mode: 0644]
test/ELF/as-needed-no-reloc.s [new file with mode: 0644]
test/ELF/as-needed.s [new file with mode: 0644]
test/ELF/auxiliary.s [new file with mode: 0644]
test/ELF/avoid-empty-program-headers.s [new file with mode: 0644]
test/ELF/bad-archive.s [new file with mode: 0644]
test/ELF/basic-aarch64.s [new file with mode: 0644]
test/ELF/basic-avr.s [new file with mode: 0644]
test/ELF/basic-freebsd.s [new file with mode: 0644]
test/ELF/basic-mips.s [new file with mode: 0644]
test/ELF/basic-ppc.s [new file with mode: 0644]
test/ELF/basic-sparcv9.s [new file with mode: 0644]
test/ELF/basic.s [new file with mode: 0644]
test/ELF/basic32.s [new file with mode: 0644]
test/ELF/basic64be.s [new file with mode: 0644]
test/ELF/bss-start-common.s [new file with mode: 0644]
test/ELF/bss.s [new file with mode: 0644]
test/ELF/bsymbolic-undef.s [new file with mode: 0644]
test/ELF/bsymbolic.s [new file with mode: 0644]
test/ELF/build-id.s [new file with mode: 0644]
test/ELF/color-diagnostics.test [new file with mode: 0644]
test/ELF/combrelocs.s [new file with mode: 0644]
test/ELF/comdat-linkonce.s [new file with mode: 0644]
test/ELF/comdat.s [new file with mode: 0644]
test/ELF/comment-gc.s [new file with mode: 0644]
test/ELF/common.s [new file with mode: 0644]
test/ELF/compatible-section-types.s [new file with mode: 0644]
test/ELF/compress-debug-sections.s [new file with mode: 0644]
test/ELF/compressed-debug-input.s [new file with mode: 0644]
test/ELF/conflict.s [new file with mode: 0644]
test/ELF/copy-errors.s [new file with mode: 0644]
test/ELF/copy-in-shared.s [new file with mode: 0644]
test/ELF/copy-rel-corrupted.s [new file with mode: 0644]
test/ELF/copy-rel-pie-error.s [new file with mode: 0644]
test/ELF/copy-rel-pie.s [new file with mode: 0644]
test/ELF/ctors_dtors_priority.s [new file with mode: 0644]
test/ELF/debug-gc.s [new file with mode: 0644]
test/ELF/debug-gnu-pubnames.s [new file with mode: 0644]
test/ELF/default-fill.s [new file with mode: 0644]
test/ELF/default-output.s [new file with mode: 0644]
test/ELF/defined-tls_get_addr.s [new file with mode: 0644]
test/ELF/defsym.s [new file with mode: 0644]
test/ELF/discard-locals.s [new file with mode: 0644]
test/ELF/discard-merge-locals.s [new file with mode: 0644]
test/ELF/discard-merge-unnamed.s [new file with mode: 0644]
test/ELF/discard-none.s [new file with mode: 0644]
test/ELF/dont-export-hidden.s [new file with mode: 0644]
test/ELF/driver-access.test [new file with mode: 0644]
test/ELF/driver.test [new file with mode: 0644]
test/ELF/dso-undef-size.s [new file with mode: 0644]
test/ELF/dso_handle.s [new file with mode: 0644]
test/ELF/dt_flags.s [new file with mode: 0644]
test/ELF/dt_tags.s [new file with mode: 0644]
test/ELF/dtrace-r.test [new file with mode: 0644]
test/ELF/duplicated-plt-entry.s [new file with mode: 0644]
test/ELF/duplicated-synthetic-sym.s [new file with mode: 0644]
test/ELF/dynamic-got-rela.s [new file with mode: 0644]
test/ELF/dynamic-got.s [new file with mode: 0644]
test/ELF/dynamic-list-extern.s [new file with mode: 0644]
test/ELF/dynamic-list.s [new file with mode: 0644]
test/ELF/dynamic-reloc-in-ro.s [new file with mode: 0644]
test/ELF/dynamic-reloc-index.s [new file with mode: 0644]
test/ELF/dynamic-reloc-weak.s [new file with mode: 0644]
test/ELF/dynamic-reloc.s [new file with mode: 0644]
test/ELF/dynamic.s [new file with mode: 0644]
test/ELF/dynsym-pie.s [new file with mode: 0644]
test/ELF/early-exit-for-bad-paths.s [new file with mode: 0644]
test/ELF/edata-etext.s [new file with mode: 0644]
test/ELF/eh-align-cie.s [new file with mode: 0644]
test/ELF/eh-frame-begin-end.s [new file with mode: 0644]
test/ELF/eh-frame-dyn-rel.s [new file with mode: 0644]
test/ELF/eh-frame-gc.s [new file with mode: 0644]
test/ELF/eh-frame-gc2.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-abs-fde.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-augmentation.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-icf.s [new file with mode: 0644]
test/ELF/eh-frame-hdr-no-out2.s [new file with mode: 0644]
test/ELF/eh-frame-hdr.s [new file with mode: 0644]
test/ELF/eh-frame-marker.s [new file with mode: 0644]
test/ELF/eh-frame-merge.s [new file with mode: 0644]
test/ELF/eh-frame-multilpe-cie.s [new file with mode: 0644]
test/ELF/eh-frame-plt.s [new file with mode: 0644]
test/ELF/eh-frame-rel.s [new file with mode: 0644]
test/ELF/eh-frame-type.test [new file with mode: 0644]
test/ELF/ehdr_start.s [new file with mode: 0644]
test/ELF/ehframe-relocation.s [new file with mode: 0644]
test/ELF/emit-relocs-merge.s [new file with mode: 0644]
test/ELF/emit-relocs-shared.s [new file with mode: 0644]
test/ELF/emit-relocs.s [new file with mode: 0644]
test/ELF/empty-archive.s [new file with mode: 0644]
test/ELF/empty-pt-load.s [new file with mode: 0644]
test/ELF/empty-ver.s [new file with mode: 0644]
test/ELF/emulation.s [new file with mode: 0644]
test/ELF/end-abs.s [new file with mode: 0644]
test/ELF/end-preserve.s [new file with mode: 0644]
test/ELF/end-update.s [new file with mode: 0644]
test/ELF/end.s [new file with mode: 0644]
test/ELF/entry.s [new file with mode: 0644]
test/ELF/error-limit.test [new file with mode: 0644]
test/ELF/exclude-libs.s [new file with mode: 0644]
test/ELF/exclude.s [new file with mode: 0644]
test/ELF/fatal-warnings.s [new file with mode: 0644]
test/ELF/file-sym.s [new file with mode: 0644]
test/ELF/filter.s [new file with mode: 0644]
test/ELF/format-binary.test [new file with mode: 0644]
test/ELF/gc-absolute.s [new file with mode: 0644]
test/ELF/gc-debuginfo-tls.s [new file with mode: 0644]
test/ELF/gc-merge-local-sym.s [new file with mode: 0644]
test/ELF/gc-sections-alloc.s [new file with mode: 0644]
test/ELF/gc-sections-eh.s [new file with mode: 0644]
test/ELF/gc-sections-implicit-addend.s [new file with mode: 0644]
test/ELF/gc-sections-keep-shared-start.s [new file with mode: 0644]
test/ELF/gc-sections-local-sym.s [new file with mode: 0644]
test/ELF/gc-sections-lsda.s [new file with mode: 0644]
test/ELF/gc-sections-merge-addend.s [new file with mode: 0644]
test/ELF/gc-sections-merge-implicit-addend.s [new file with mode: 0644]
test/ELF/gc-sections-merge.s [new file with mode: 0644]
test/ELF/gc-sections-metadata-startstop.s [new file with mode: 0644]
test/ELF/gc-sections-metadata.s [new file with mode: 0644]
test/ELF/gc-sections-metadata2.s [new file with mode: 0644]
test/ELF/gc-sections-non-alloc-to-merge.s [new file with mode: 0644]
test/ELF/gc-sections-print.s [new file with mode: 0644]
test/ELF/gc-sections-protected.s [new file with mode: 0644]
test/ELF/gc-sections-shared.s [new file with mode: 0644]
test/ELF/gc-sections-synthetic.s [new file with mode: 0644]
test/ELF/gc-sections-weak.s [new file with mode: 0644]
test/ELF/gc-sections.s [new file with mode: 0644]
test/ELF/gdb-index-dup-types.s [new file with mode: 0644]
test/ELF/gdb-index-empty.s [new file with mode: 0644]
test/ELF/gdb-index-gc-sections.s [new file with mode: 0644]
test/ELF/gdb-index-ranges.s [new file with mode: 0644]
test/ELF/gdb-index.s [new file with mode: 0644]
test/ELF/global-offset-table-position-aarch64.s [new file with mode: 0644]
test/ELF/global-offset-table-position-arm.s [new file with mode: 0644]
test/ELF/global-offset-table-position-i386.s [new file with mode: 0644]
test/ELF/global-offset-table-position-mips.s [new file with mode: 0644]
test/ELF/global-offset-table-position.s [new file with mode: 0644]
test/ELF/global_offset_table.s [new file with mode: 0644]
test/ELF/global_offset_table_shared.s [new file with mode: 0644]
test/ELF/gnu-hash-table.s [new file with mode: 0644]
test/ELF/gnu-ifunc-dso.s [new file with mode: 0644]
test/ELF/gnu-ifunc-gotpcrel.s [new file with mode: 0644]
test/ELF/gnu-ifunc-i386.s [new file with mode: 0644]
test/ELF/gnu-ifunc-nosym-i386.s [new file with mode: 0644]
test/ELF/gnu-ifunc-nosym.s [new file with mode: 0644]
test/ELF/gnu-ifunc-plt-i386.s [new file with mode: 0644]
test/ELF/gnu-ifunc-plt.s [new file with mode: 0644]
test/ELF/gnu-ifunc-relative.s [new file with mode: 0644]
test/ELF/gnu-ifunc-shared.s [new file with mode: 0644]
test/ELF/gnu-ifunc.s [new file with mode: 0644]
test/ELF/gnu-unique.s [new file with mode: 0644]
test/ELF/gnustack.s [new file with mode: 0644]
test/ELF/got-aarch64.s [new file with mode: 0644]
test/ELF/got-i386.s [new file with mode: 0644]
test/ELF/got-plt-header.s [new file with mode: 0644]
test/ELF/got.s [new file with mode: 0644]
test/ELF/got32-i386.s [new file with mode: 0644]
test/ELF/got32x-i386.s [new file with mode: 0644]
test/ELF/gotpc-relax-nopic.s [new file with mode: 0644]
test/ELF/gotpc-relax-und-dso.s [new file with mode: 0644]
test/ELF/gotpc-relax.s [new file with mode: 0644]
test/ELF/gotpcrelx.s [new file with mode: 0644]
test/ELF/hidden-vis-shared.s [new file with mode: 0644]
test/ELF/i386-got-and-copy.s [new file with mode: 0644]
test/ELF/i386-gotoff-shared.s [new file with mode: 0644]
test/ELF/i386-gotpc-dynamic.s [new file with mode: 0644]
test/ELF/i386-gotpc.s [new file with mode: 0644]
test/ELF/i386-merge.s [new file with mode: 0644]
test/ELF/i386-pc16.test [new file with mode: 0644]
test/ELF/i386-pc8-pc16-addend.s [new file with mode: 0644]
test/ELF/i386-pc8.s [new file with mode: 0644]
test/ELF/i386-relative.s [new file with mode: 0644]
test/ELF/i386-relax-reloc.s [new file with mode: 0644]
test/ELF/i386-reloc-16.s [new file with mode: 0644]
test/ELF/i386-reloc-8.s [new file with mode: 0644]
test/ELF/i386-reloc-large-addend.s [new file with mode: 0644]
test/ELF/i386-reloc-range.s [new file with mode: 0644]
test/ELF/i386-reloc8-reloc16-addend.s [new file with mode: 0644]
test/ELF/i386-tls-got.s [new file with mode: 0644]
test/ELF/i386-tls-ie-shared.s [new file with mode: 0644]
test/ELF/icf-absolute.s [new file with mode: 0644]
test/ELF/icf-comdat.s [new file with mode: 0644]
test/ELF/icf-i386.s [new file with mode: 0644]
test/ELF/icf-merge-sec.s [new file with mode: 0644]
test/ELF/icf-merge.s [new file with mode: 0644]
test/ELF/icf-non-mergeable.s [new file with mode: 0644]
test/ELF/icf-none.s [new file with mode: 0644]
test/ELF/icf1.s [new file with mode: 0644]
test/ELF/icf2.s [new file with mode: 0644]
test/ELF/icf3.s [new file with mode: 0644]
test/ELF/icf4.s [new file with mode: 0644]
test/ELF/icf5.s [new file with mode: 0644]
test/ELF/icf6.s [new file with mode: 0644]
test/ELF/icf7.s [new file with mode: 0644]
test/ELF/icf8.s [new file with mode: 0644]
test/ELF/icf9.s [new file with mode: 0644]
test/ELF/image-base.s [new file with mode: 0644]
test/ELF/incompatible-ar-first.s [new file with mode: 0644]
test/ELF/incompatible-section-flags.s [new file with mode: 0644]
test/ELF/incompatible-section-types2.s [new file with mode: 0644]
test/ELF/incompatible.s [new file with mode: 0644]
test/ELF/init-fini-progbits.s [new file with mode: 0644]
test/ELF/init-fini.s [new file with mode: 0644]
test/ELF/init_fini_priority.s [new file with mode: 0644]
test/ELF/invalid-cie-length.s [new file with mode: 0644]
test/ELF/invalid-cie-length2.s [new file with mode: 0644]
test/ELF/invalid-cie-length3.s [new file with mode: 0644]
test/ELF/invalid-cie-length4.s [new file with mode: 0644]
test/ELF/invalid-cie-length5.s [new file with mode: 0644]
test/ELF/invalid-cie-reference.s [new file with mode: 0644]
test/ELF/invalid-dynamic-list.test [new file with mode: 0644]
test/ELF/invalid-fde-rel.s [new file with mode: 0644]
test/ELF/invalid-linkerscript.test [new file with mode: 0644]
test/ELF/invalid-relocations.test [new file with mode: 0644]
test/ELF/invalid-z.s [new file with mode: 0644]
test/ELF/invalid/Inputs/binding.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/broken-relaxation-x64.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/cie-version2.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/common-symbol-alignment.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/common-symbol-alignment2.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/data-encoding.a [new file with mode: 0644]
test/ELF/invalid/Inputs/dynamic-section-sh_size.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/file-class.a [new file with mode: 0644]
test/ELF/invalid/Inputs/invalid-e_shnum.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/mips-invalid-options-descriptor.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/multiple-eh-relocs.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/section-alignment-notpow2.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/section-index.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/section-index2.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/shentsize-zero.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/sht-group.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/symbol-index.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/symbol-name-offset.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/symtab-sh_info.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/symtab-sh_info2.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/symtab-sh_info3.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/tls-symbol.elf [new file with mode: 0644]
test/ELF/invalid/Inputs/too-short.elf [new file with mode: 0644]
test/ELF/invalid/broken-relaxation-x64.test [new file with mode: 0644]
test/ELF/invalid/common-symbol-alignment.s [new file with mode: 0644]
test/ELF/invalid/dynamic-section-size.s [new file with mode: 0644]
test/ELF/invalid/eh-frame-hdr-no-out.s [new file with mode: 0644]
test/ELF/invalid/invalid-debug-relocations.test [new file with mode: 0644]
test/ELF/invalid/invalid-e_shnum.s [new file with mode: 0644]
test/ELF/invalid/invalid-elf.test [new file with mode: 0644]
test/ELF/invalid/invalid-relocation-x64.test [new file with mode: 0644]
test/ELF/invalid/merge-invalid-size.s [new file with mode: 0644]
test/ELF/invalid/mips-invalid-options-descriptor.s [new file with mode: 0644]
test/ELF/invalid/section-alignment.test [new file with mode: 0644]
test/ELF/invalid/section-alignment2.s [new file with mode: 0644]
test/ELF/invalid/sht-group.s [new file with mode: 0644]
test/ELF/invalid/symbol-index.s [new file with mode: 0644]
test/ELF/invalid/symbol-name.s [new file with mode: 0644]
test/ELF/invalid/symtab-sh-info.s [new file with mode: 0644]
test/ELF/invalid/symtab-symbols.test [new file with mode: 0644]
test/ELF/invalid/tls-symbol.s [new file with mode: 0644]
test/ELF/invalid/too-short.s [new file with mode: 0644]
test/ELF/invalid/verdef-no-symtab.test [new file with mode: 0644]
test/ELF/libsearch.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/comdat-gc.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/compress-debug-sections.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/exclude-multiple1.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/exclude-multiple2.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/filename-spec.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/implicit-program-header.script [new file with mode: 0644]
test/ELF/linkerscript/Inputs/include.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/keep.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/lazy-symbols.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/libsearch-dyn.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/libsearch-st.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/merge-sections-reloc.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/notinclude.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/segment-start.script [new file with mode: 0644]
test/ELF/linkerscript/Inputs/shared.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/sort-nested.s [new file with mode: 0644]
test/ELF/linkerscript/Inputs/sort.s [new file with mode: 0644]
test/ELF/linkerscript/absolute-expr.s [new file with mode: 0644]
test/ELF/linkerscript/absolute.s [new file with mode: 0644]
test/ELF/linkerscript/addr-zero.s [new file with mode: 0644]
test/ELF/linkerscript/addr.s [new file with mode: 0644]
test/ELF/linkerscript/align-empty.s [new file with mode: 0644]
test/ELF/linkerscript/align.s [new file with mode: 0644]
test/ELF/linkerscript/alignof.s [new file with mode: 0644]
test/ELF/linkerscript/alternate-sections.s [new file with mode: 0644]
test/ELF/linkerscript/arm-exidx-phdrs.s [new file with mode: 0644]
test/ELF/linkerscript/arm-lscript.s [new file with mode: 0644]
test/ELF/linkerscript/assert.s [new file with mode: 0644]
test/ELF/linkerscript/at-addr.s [new file with mode: 0644]
test/ELF/linkerscript/at.s [new file with mode: 0644]
test/ELF/linkerscript/bss-fill.s [new file with mode: 0644]
test/ELF/linkerscript/comdat-gc.s [new file with mode: 0644]
test/ELF/linkerscript/common-assign.s [new file with mode: 0644]
test/ELF/linkerscript/common.s [new file with mode: 0644]
test/ELF/linkerscript/compress-debug-sections.s [new file with mode: 0644]
test/ELF/linkerscript/constructor.s [new file with mode: 0644]
test/ELF/linkerscript/data-commands-gc.s [new file with mode: 0644]
test/ELF/linkerscript/data-commands.s [new file with mode: 0644]
test/ELF/linkerscript/data-segment-relro.s [new file with mode: 0644]
test/ELF/linkerscript/define.s [new file with mode: 0644]
test/ELF/linkerscript/diagnostic.s [new file with mode: 0644]
test/ELF/linkerscript/discard-interp.s [new file with mode: 0644]
test/ELF/linkerscript/discard-print-gc.s [new file with mode: 0644]
test/ELF/linkerscript/discard-section-err.s [new file with mode: 0644]
test/ELF/linkerscript/discard-section-metadata.s [new file with mode: 0644]
test/ELF/linkerscript/discard-section.s [new file with mode: 0644]
test/ELF/linkerscript/dot-is-not-abs.s [new file with mode: 0644]
test/ELF/linkerscript/double-bss.s [new file with mode: 0644]
test/ELF/linkerscript/dynamic-sym.s [new file with mode: 0644]
test/ELF/linkerscript/dynamic.s [new file with mode: 0644]
test/ELF/linkerscript/early-assign-symbol.s [new file with mode: 0644]
test/ELF/linkerscript/edata-etext.s [new file with mode: 0644]
test/ELF/linkerscript/eh-frame-hdr.s [new file with mode: 0644]
test/ELF/linkerscript/eh-frame-reloc-out-of-range.s [new file with mode: 0644]
test/ELF/linkerscript/eh-frame.s [new file with mode: 0644]
test/ELF/linkerscript/ehdr_start.s [new file with mode: 0644]
test/ELF/linkerscript/emit-reloc.s [new file with mode: 0644]
test/ELF/linkerscript/emit-relocs-discard.s [new file with mode: 0644]
test/ELF/linkerscript/emit-relocs-ehframe-discard.s [new file with mode: 0644]
test/ELF/linkerscript/emit-relocs-multiple.s [new file with mode: 0644]
test/ELF/linkerscript/empty-load.s [new file with mode: 0644]
test/ELF/linkerscript/empty-tls.s [new file with mode: 0644]
test/ELF/linkerscript/entry.s [new file with mode: 0644]
test/ELF/linkerscript/exclude-multiple.s [new file with mode: 0644]
test/ELF/linkerscript/excludefile.s [new file with mode: 0644]
test/ELF/linkerscript/exidx-crash.s [new file with mode: 0644]
test/ELF/linkerscript/expr-invalid-sec.s [new file with mode: 0644]
test/ELF/linkerscript/expr-sections.s [new file with mode: 0644]
test/ELF/linkerscript/extend-pt-load.s [new file with mode: 0644]
test/ELF/linkerscript/filename-spec.s [new file with mode: 0644]
test/ELF/linkerscript/fill-exec-sections.s [new file with mode: 0644]
test/ELF/linkerscript/fill.s [new file with mode: 0644]
test/ELF/linkerscript/got-write-offset.s [new file with mode: 0644]
test/ELF/linkerscript/group.s [new file with mode: 0644]
test/ELF/linkerscript/header-addr.s [new file with mode: 0644]
test/ELF/linkerscript/huge-temporary-file.s [new file with mode: 0644]
test/ELF/linkerscript/implicit-program-header.s [new file with mode: 0644]
test/ELF/linkerscript/input-order.s [new file with mode: 0644]
test/ELF/linkerscript/input-sec-dup.s [new file with mode: 0644]
test/ELF/linkerscript/lazy-symbols.s [new file with mode: 0644]
test/ELF/linkerscript/linkerscript.s [new file with mode: 0644]
test/ELF/linkerscript/loadaddr.s [new file with mode: 0644]
test/ELF/linkerscript/locationcountererr.s [new file with mode: 0644]
test/ELF/linkerscript/locationcountererr2.s [new file with mode: 0644]
test/ELF/linkerscript/memory.s [new file with mode: 0644]
test/ELF/linkerscript/merge-sections-reloc.s [new file with mode: 0644]
test/ELF/linkerscript/merge-sections-syms.s [new file with mode: 0644]
test/ELF/linkerscript/merge-sections.s [new file with mode: 0644]
test/ELF/linkerscript/multi-sections-constraint.s [new file with mode: 0644]
test/ELF/linkerscript/multiple-tbss.s [new file with mode: 0644]
test/ELF/linkerscript/no-pt-load.s [new file with mode: 0644]
test/ELF/linkerscript/no-space.s [new file with mode: 0644]
test/ELF/linkerscript/noload.s [new file with mode: 0644]
test/ELF/linkerscript/non-absolute.s [new file with mode: 0644]
test/ELF/linkerscript/non-absolute2.s [new file with mode: 0644]
test/ELF/linkerscript/non-alloc-segment.s [new file with mode: 0644]
test/ELF/linkerscript/non-alloc.s [new file with mode: 0644]
test/ELF/linkerscript/numbers.s [new file with mode: 0644]
test/ELF/linkerscript/obj-symbol-value.s [new file with mode: 0644]
test/ELF/linkerscript/openbsd-bootdata.s [new file with mode: 0644]
test/ELF/linkerscript/openbsd-randomize.s [new file with mode: 0644]
test/ELF/linkerscript/openbsd-wxneeded.s [new file with mode: 0644]
test/ELF/linkerscript/operators.s [new file with mode: 0644]
test/ELF/linkerscript/orphan-align.s [new file with mode: 0644]
test/ELF/linkerscript/orphan-first-cmd.s [new file with mode: 0644]
test/ELF/linkerscript/orphan.s [new file with mode: 0644]
test/ELF/linkerscript/orphans.s [new file with mode: 0644]
test/ELF/linkerscript/ouputformat.s [new file with mode: 0644]
test/ELF/linkerscript/out-of-order.s [new file with mode: 0644]
test/ELF/linkerscript/output-too-large.s [new file with mode: 0644]
test/ELF/linkerscript/outputarch.s [new file with mode: 0644]
test/ELF/linkerscript/outsections-addr.s [new file with mode: 0644]
test/ELF/linkerscript/page-size-align.s [new file with mode: 0644]
test/ELF/linkerscript/page-size.s [new file with mode: 0644]
test/ELF/linkerscript/phdr-check.s [new file with mode: 0644]
test/ELF/linkerscript/phdrs-flags.s [new file with mode: 0644]
test/ELF/linkerscript/phdrs.s [new file with mode: 0644]
test/ELF/linkerscript/pt_gnu_eh_frame.s [new file with mode: 0644]
test/ELF/linkerscript/repsection-symbol.s [new file with mode: 0644]
test/ELF/linkerscript/repsection-va.s [new file with mode: 0644]
test/ELF/linkerscript/rosegment.s [new file with mode: 0644]
test/ELF/linkerscript/searchdir.s [new file with mode: 0644]
test/ELF/linkerscript/section-align.s [new file with mode: 0644]
test/ELF/linkerscript/section-metadata.s [new file with mode: 0644]
test/ELF/linkerscript/sections-constraint.s [new file with mode: 0644]
test/ELF/linkerscript/sections-constraint2.s [new file with mode: 0644]
test/ELF/linkerscript/sections-constraint3.s [new file with mode: 0644]
test/ELF/linkerscript/sections-constraint4.s [new file with mode: 0644]
test/ELF/linkerscript/sections-constraint5.s [new file with mode: 0644]
test/ELF/linkerscript/sections-gc.s [new file with mode: 0644]
test/ELF/linkerscript/sections-gc2.s [new file with mode: 0644]
test/ELF/linkerscript/sections-keep.s [new file with mode: 0644]
test/ELF/linkerscript/sections-padding.s [new file with mode: 0644]
test/ELF/linkerscript/sections-sort.s [new file with mode: 0644]
test/ELF/linkerscript/sections.s [new file with mode: 0644]
test/ELF/linkerscript/segment-none.s [new file with mode: 0644]
test/ELF/linkerscript/segment-start.s [new file with mode: 0644]
test/ELF/linkerscript/sizeof.s [new file with mode: 0644]
test/ELF/linkerscript/sizeofheaders.s [new file with mode: 0644]
test/ELF/linkerscript/sort-constructors.s [new file with mode: 0644]
test/ELF/linkerscript/sort-init.s [new file with mode: 0644]
test/ELF/linkerscript/sort-nested.s [new file with mode: 0644]
test/ELF/linkerscript/sort-non-script.s [new file with mode: 0644]
test/ELF/linkerscript/sort.s [new file with mode: 0644]
test/ELF/linkerscript/sort2.s [new file with mode: 0644]
test/ELF/linkerscript/start-end.s [new file with mode: 0644]
test/ELF/linkerscript/subalign.s [new file with mode: 0644]
test/ELF/linkerscript/symbol-assignexpr.s [new file with mode: 0644]
test/ELF/linkerscript/symbol-conflict.s [new file with mode: 0644]
test/ELF/linkerscript/symbol-memoryexpr.s [new file with mode: 0644]
test/ELF/linkerscript/symbol-only.s [new file with mode: 0644]
test/ELF/linkerscript/symbol-reserved.s [new file with mode: 0644]
test/ELF/linkerscript/symbolreferenced.s [new file with mode: 0644]
test/ELF/linkerscript/symbols-non-alloc.s [new file with mode: 0644]
test/ELF/linkerscript/symbols-synthetic.s [new file with mode: 0644]
test/ELF/linkerscript/symbols.s [new file with mode: 0644]
test/ELF/linkerscript/tbss.s [new file with mode: 0644]
test/ELF/linkerscript/ttext-script.s [new file with mode: 0644]
test/ELF/linkerscript/undef.s [new file with mode: 0644]
test/ELF/linkerscript/unused-synthetic.s [new file with mode: 0644]
test/ELF/linkerscript/va.s [new file with mode: 0644]
test/ELF/linkerscript/visibility.s [new file with mode: 0644]
test/ELF/linkerscript/wildcards.s [new file with mode: 0644]
test/ELF/linkerscript/wildcards2.s [new file with mode: 0644]
test/ELF/lit.local.cfg [new file with mode: 0644]
test/ELF/llvm33-rela-outside-group.s [new file with mode: 0644]
test/ELF/local-dynamic.s [new file with mode: 0644]
test/ELF/local-got-pie.s [new file with mode: 0644]
test/ELF/local-got-shared.s [new file with mode: 0644]
test/ELF/local-got.s [new file with mode: 0644]
test/ELF/local-undefined-symbol.s [new file with mode: 0644]
test/ELF/local.s [new file with mode: 0644]
test/ELF/lto/Inputs/archive-2.ll [new file with mode: 0644]
test/ELF/lto/Inputs/archive-3.ll [new file with mode: 0644]
test/ELF/lto/Inputs/archive.ll [new file with mode: 0644]
test/ELF/lto/Inputs/available-externally.ll [new file with mode: 0644]
test/ELF/lto/Inputs/cache.ll [new file with mode: 0644]
test/ELF/lto/Inputs/comdat.s [new file with mode: 0644]
test/ELF/lto/Inputs/common.s [new file with mode: 0644]
test/ELF/lto/Inputs/common3.ll [new file with mode: 0644]
test/ELF/lto/Inputs/defsym-bar.ll [new file with mode: 0644]
test/ELF/lto/Inputs/drop-debug-info.bc [new file with mode: 0644]
test/ELF/lto/Inputs/drop-linkage.ll [new file with mode: 0644]
test/ELF/lto/Inputs/duplicated-name.ll [new file with mode: 0644]
test/ELF/lto/Inputs/dynsym.s [new file with mode: 0644]
test/ELF/lto/Inputs/internalize-exportdyn.ll [new file with mode: 0644]
test/ELF/lto/Inputs/internalize-undef.ll [new file with mode: 0644]
test/ELF/lto/Inputs/irmover-error.ll [new file with mode: 0644]
test/ELF/lto/Inputs/linkonce-odr.ll [new file with mode: 0644]
test/ELF/lto/Inputs/linkonce.ll [new file with mode: 0644]
test/ELF/lto/Inputs/relocation-model-pic.ll [new file with mode: 0644]
test/ELF/lto/Inputs/resolution.s [new file with mode: 0644]
test/ELF/lto/Inputs/save-temps.ll [new file with mode: 0644]
test/ELF/lto/Inputs/shared.s [new file with mode: 0644]
test/ELF/lto/Inputs/start-lib1.ll [new file with mode: 0644]
test/ELF/lto/Inputs/start-lib2.ll [new file with mode: 0644]
test/ELF/lto/Inputs/thin1.ll [new file with mode: 0644]
test/ELF/lto/Inputs/thin2.ll [new file with mode: 0644]
test/ELF/lto/Inputs/thinlto.ll [new file with mode: 0644]
test/ELF/lto/Inputs/tls-mixed.s [new file with mode: 0644]
test/ELF/lto/Inputs/type-merge.ll [new file with mode: 0644]
test/ELF/lto/Inputs/type-merge2.ll [new file with mode: 0644]
test/ELF/lto/Inputs/undef-mixed.s [new file with mode: 0644]
test/ELF/lto/Inputs/unnamed-addr-drop.ll [new file with mode: 0644]
test/ELF/lto/Inputs/unnamed-addr-lib.s [new file with mode: 0644]
test/ELF/lto/Inputs/visibility.s [new file with mode: 0644]
test/ELF/lto/Inputs/wrap-bar.ll [new file with mode: 0644]
test/ELF/lto/archive-2.ll [new file with mode: 0644]
test/ELF/lto/archive-3.ll [new file with mode: 0644]
test/ELF/lto/archive-no-index.ll [new file with mode: 0644]
test/ELF/lto/archive.ll [new file with mode: 0644]
test/ELF/lto/asmundef.ll [new file with mode: 0644]
test/ELF/lto/available-externally.ll [new file with mode: 0644]
test/ELF/lto/bitcode-nodatalayout.ll [new file with mode: 0644]
test/ELF/lto/cache.ll [new file with mode: 0644]
test/ELF/lto/codemodel.ll [new file with mode: 0644]
test/ELF/lto/combined-lto-object-name.ll [new file with mode: 0644]
test/ELF/lto/comdat.ll [new file with mode: 0644]
test/ELF/lto/comdat2.ll [new file with mode: 0644]
test/ELF/lto/common.ll [new file with mode: 0644]
test/ELF/lto/common2.ll [new file with mode: 0644]
test/ELF/lto/common3.ll [new file with mode: 0644]
test/ELF/lto/ctors.ll [new file with mode: 0644]
test/ELF/lto/defsym.ll [new file with mode: 0644]
test/ELF/lto/discard-value-names.ll [new file with mode: 0644]
test/ELF/lto/drop-debug-info.ll [new file with mode: 0644]
test/ELF/lto/drop-linkage.ll [new file with mode: 0644]
test/ELF/lto/duplicated-name.ll [new file with mode: 0644]
test/ELF/lto/duplicated.ll [new file with mode: 0644]
test/ELF/lto/dynamic-list.ll [new file with mode: 0644]
test/ELF/lto/dynsym.ll [new file with mode: 0644]
test/ELF/lto/inline-asm.ll [new file with mode: 0644]
test/ELF/lto/internalize-basic.ll [new file with mode: 0644]
test/ELF/lto/internalize-exportdyn.ll [new file with mode: 0644]
test/ELF/lto/internalize-llvmused.ll [new file with mode: 0644]
test/ELF/lto/internalize-undef.ll [new file with mode: 0644]
test/ELF/lto/internalize-version-script.ll [new file with mode: 0644]
test/ELF/lto/irmover-error.ll [new file with mode: 0644]
test/ELF/lto/linkage.ll [new file with mode: 0644]
test/ELF/lto/linkonce-odr.ll [new file with mode: 0644]
test/ELF/lto/linkonce.ll [new file with mode: 0644]
test/ELF/lto/lto-start.ll [new file with mode: 0644]
test/ELF/lto/ltopasses-basic.ll [new file with mode: 0644]
test/ELF/lto/ltopasses-custom.ll [new file with mode: 0644]
test/ELF/lto/metadata.ll [new file with mode: 0644]
test/ELF/lto/mix-platforms.ll [new file with mode: 0644]
test/ELF/lto/module-asm.ll [new file with mode: 0644]
test/ELF/lto/opt-level.ll [new file with mode: 0644]
test/ELF/lto/opt-remarks.ll [new file with mode: 0644]
test/ELF/lto/parallel-internalize.ll [new file with mode: 0644]
test/ELF/lto/parallel.ll [new file with mode: 0644]
test/ELF/lto/pic.ll [new file with mode: 0644]
test/ELF/lto/relax-relocs.ll [new file with mode: 0644]
test/ELF/lto/relocation-model.ll [new file with mode: 0644]
test/ELF/lto/resolution.ll [new file with mode: 0644]
test/ELF/lto/save-temps.ll [new file with mode: 0644]
test/ELF/lto/shlib-undefined.ll [new file with mode: 0644]
test/ELF/lto/start-lib.ll [new file with mode: 0644]
test/ELF/lto/thin-archivecollision.ll [new file with mode: 0644]
test/ELF/lto/thinlto.ll [new file with mode: 0644]
test/ELF/lto/timepasses.ll [new file with mode: 0644]
test/ELF/lto/tls-mixed.ll [new file with mode: 0644]
test/ELF/lto/tls-preserve.ll [new file with mode: 0644]
test/ELF/lto/type-merge.ll [new file with mode: 0644]
test/ELF/lto/type-merge2.ll [new file with mode: 0644]
test/ELF/lto/undef-mixed.ll [new file with mode: 0644]
test/ELF/lto/undef-weak.ll [new file with mode: 0644]
test/ELF/lto/undef.ll [new file with mode: 0644]
test/ELF/lto/undefined-puts.ll [new file with mode: 0644]
test/ELF/lto/unnamed-addr-comdat.ll [new file with mode: 0644]
test/ELF/lto/unnamed-addr-drop.ll [new file with mode: 0644]
test/ELF/lto/unnamed-addr-lib.ll [new file with mode: 0644]
test/ELF/lto/unnamed-addr.ll [new file with mode: 0644]
test/ELF/lto/verify-invalid.ll [new file with mode: 0644]
test/ELF/lto/version-script.ll [new file with mode: 0644]
test/ELF/lto/visibility.ll [new file with mode: 0644]
test/ELF/lto/weak.ll [new file with mode: 0644]
test/ELF/lto/wrap-1.ll [new file with mode: 0644]
test/ELF/lto/wrap-2.ll [new file with mode: 0644]
test/ELF/many-alloc-sections.s [new file with mode: 0644]
test/ELF/many-sections.s [new file with mode: 0644]
test/ELF/map-file.s [new file with mode: 0644]
test/ELF/map-gc-sections.s [new file with mode: 0644]
test/ELF/merge-reloc.s [new file with mode: 0644]
test/ELF/merge-section-types.s [new file with mode: 0644]
test/ELF/merge-shared-str.s [new file with mode: 0644]
test/ELF/merge-shared.s [new file with mode: 0644]
test/ELF/merge-string-align.s [new file with mode: 0644]
test/ELF/merge-string-empty.s [new file with mode: 0644]
test/ELF/merge-string-error.s [new file with mode: 0644]
test/ELF/merge-string-no-null.s [new file with mode: 0644]
test/ELF/merge-string.s [new file with mode: 0644]
test/ELF/merge-sym.s [new file with mode: 0644]
test/ELF/merge.s [new file with mode: 0644]
test/ELF/mips-26-mask.s [new file with mode: 0644]
test/ELF/mips-26.s [new file with mode: 0644]
test/ELF/mips-32.s [new file with mode: 0644]
test/ELF/mips-64-disp.s [new file with mode: 0644]
test/ELF/mips-64-got.s [new file with mode: 0644]
test/ELF/mips-64-gprel-so.s [new file with mode: 0644]
test/ELF/mips-64-rels.s [new file with mode: 0644]
test/ELF/mips-64.s [new file with mode: 0644]
test/ELF/mips-align-err.s [new file with mode: 0644]
test/ELF/mips-call-hilo.s [new file with mode: 0644]
test/ELF/mips-call16.s [new file with mode: 0644]
test/ELF/mips-dynamic.s [new file with mode: 0644]
test/ELF/mips-dynsym-sort.s [new file with mode: 0644]
test/ELF/mips-elf-flags-err.s [new file with mode: 0644]
test/ELF/mips-elf-flags.s [new file with mode: 0644]
test/ELF/mips-gnu-hash.s [new file with mode: 0644]
test/ELF/mips-got-and-copy.s [new file with mode: 0644]
test/ELF/mips-got-extsym.s [new file with mode: 0644]
test/ELF/mips-got-hilo.s [new file with mode: 0644]
test/ELF/mips-got-page.s [new file with mode: 0644]
test/ELF/mips-got-redundant.s [new file with mode: 0644]
test/ELF/mips-got-relocs.s [new file with mode: 0644]
test/ELF/mips-got-string.s [new file with mode: 0644]
test/ELF/mips-got-weak.s [new file with mode: 0644]
test/ELF/mips-got16-relocatable.s [new file with mode: 0644]
test/ELF/mips-got16.s [new file with mode: 0644]
test/ELF/mips-gp-disp.s [new file with mode: 0644]
test/ELF/mips-gp-ext.s [new file with mode: 0644]
test/ELF/mips-gp-local.s [new file with mode: 0644]
test/ELF/mips-gp-lowest.s [new file with mode: 0644]
test/ELF/mips-gprel-sec.s [new file with mode: 0644]
test/ELF/mips-gprel32-relocs-gp0.s [new file with mode: 0644]
test/ELF/mips-gprel32-relocs.s [new file with mode: 0644]
test/ELF/mips-higher-highest.s [new file with mode: 0644]
test/ELF/mips-hilo-gp-disp.s [new file with mode: 0644]
test/ELF/mips-hilo-hi-only.s [new file with mode: 0644]
test/ELF/mips-hilo.s [new file with mode: 0644]
test/ELF/mips-jalr.test [new file with mode: 0644]
test/ELF/mips-lo16-not-relative.s [new file with mode: 0644]
test/ELF/mips-merge-abiflags.s [new file with mode: 0644]
test/ELF/mips-n32-emul.s [new file with mode: 0644]
test/ELF/mips-n32-rels.s [new file with mode: 0644]
test/ELF/mips-no-objects.s [new file with mode: 0644]
test/ELF/mips-nonalloc.s [new file with mode: 0644]
test/ELF/mips-npic-call-pic-os.s [new file with mode: 0644]
test/ELF/mips-npic-call-pic-script.s [new file with mode: 0644]
test/ELF/mips-npic-call-pic.s [new file with mode: 0644]
test/ELF/mips-options-r.test [new file with mode: 0644]
test/ELF/mips-options.s [new file with mode: 0644]
test/ELF/mips-pc-relocs.s [new file with mode: 0644]
test/ELF/mips-plt-copy.s [new file with mode: 0644]
test/ELF/mips-plt-r6.s [new file with mode: 0644]
test/ELF/mips-reginfo.s [new file with mode: 0644]
test/ELF/mips-relocatable.s [new file with mode: 0644]
test/ELF/mips-sto-pic-flag.s [new file with mode: 0644]
test/ELF/mips-sto-plt.s [new file with mode: 0644]
test/ELF/mips-tls-64.s [new file with mode: 0644]
test/ELF/mips-tls-hilo.s [new file with mode: 0644]
test/ELF/mips-tls-static-64.s [new file with mode: 0644]
test/ELF/mips-tls-static.s [new file with mode: 0644]
test/ELF/mips-tls.s [new file with mode: 0644]
test/ELF/mips-xgot-order.s [new file with mode: 0644]
test/ELF/mips64-eh-abs-reloc.s [new file with mode: 0644]
test/ELF/new-dtags.test [new file with mode: 0644]
test/ELF/no-augmentation.s [new file with mode: 0644]
test/ELF/no-dynamic-linker.s [new file with mode: 0644]
test/ELF/no-inhibit-exec.s [new file with mode: 0644]
test/ELF/no-merge.s [new file with mode: 0644]
test/ELF/no-obj.s [new file with mode: 0644]
test/ELF/no-plt-shared.s [new file with mode: 0644]
test/ELF/no-soname.s [new file with mode: 0644]
test/ELF/no-symtab.s [new file with mode: 0644]
test/ELF/no-undefined.s [new file with mode: 0644]
test/ELF/non-abs-reloc.s [new file with mode: 0644]
test/ELF/noplt-pie.s [new file with mode: 0644]
test/ELF/note-contiguous.s [new file with mode: 0644]
test/ELF/note-loadaddr.c [new file with mode: 0644]
test/ELF/note-multiple.s [new file with mode: 0644]
test/ELF/note.s [new file with mode: 0644]
test/ELF/oformat-binary-ttext.s [new file with mode: 0644]
test/ELF/oformat-binary.s [new file with mode: 0644]
test/ELF/openbsd-randomize.s [new file with mode: 0644]
test/ELF/openbsd-wxneeded.s [new file with mode: 0644]
test/ELF/output-section.s [new file with mode: 0644]
test/ELF/phdr-align.s [new file with mode: 0644]
test/ELF/pie-weak.s [new file with mode: 0644]
test/ELF/pie.s [new file with mode: 0644]
test/ELF/plt-aarch64.s [new file with mode: 0644]
test/ELF/plt-i686.s [new file with mode: 0644]
test/ELF/plt.s [new file with mode: 0644]
test/ELF/ppc-relocs.s [new file with mode: 0644]
test/ELF/ppc64-addr16-error.s [new file with mode: 0644]
test/ELF/ppc64-rel-calls.s [new file with mode: 0644]
test/ELF/ppc64-relocs.s [new file with mode: 0644]
test/ELF/ppc64-shared-rel-toc.s [new file with mode: 0644]
test/ELF/ppc64-toc-restore.s [new file with mode: 0644]
test/ELF/ppc64-weak-undef-call-shared.s [new file with mode: 0644]
test/ELF/ppc64-weak-undef-call.s [new file with mode: 0644]
test/ELF/pre_init_fini_array.s [new file with mode: 0644]
test/ELF/pre_init_fini_array_missing.s [new file with mode: 0644]
test/ELF/progname.s [new file with mode: 0644]
test/ELF/program-header-layout.s [new file with mode: 0644]
test/ELF/protected-shared.s [new file with mode: 0644]
test/ELF/rel-offset.s [new file with mode: 0644]
test/ELF/relative-dynamic-reloc-pie.s [new file with mode: 0644]
test/ELF/relative-dynamic-reloc-ppc64.s [new file with mode: 0644]
test/ELF/relative-dynamic-reloc.s [new file with mode: 0644]
test/ELF/relocatable-bss.s [new file with mode: 0644]
test/ELF/relocatable-comdat-multiple.s [new file with mode: 0644]
test/ELF/relocatable-comdat.s [new file with mode: 0644]
test/ELF/relocatable-comment.s [new file with mode: 0644]
test/ELF/relocatable-common.s [new file with mode: 0644]
test/ELF/relocatable-compressed-input.s [new file with mode: 0644]
test/ELF/relocatable-eh-frame-hdr.s [new file with mode: 0644]
test/ELF/relocatable-eh-frame.s [new file with mode: 0644]
test/ELF/relocatable-ehframe.s [new file with mode: 0644]
test/ELF/relocatable-empty-archive.s [new file with mode: 0644]
test/ELF/relocatable-local-sym.s [new file with mode: 0644]
test/ELF/relocatable-non-alloc.s [new file with mode: 0644]
test/ELF/relocatable-reloc.s [new file with mode: 0644]
test/ELF/relocatable-script.s [new file with mode: 0644]
test/ELF/relocatable-section-symbol.s [new file with mode: 0644]
test/ELF/relocatable-sections.s [new file with mode: 0644]
test/ELF/relocatable-symbol-name.s [new file with mode: 0644]
test/ELF/relocatable-symbols.s [new file with mode: 0644]
test/ELF/relocatable-tls.s [new file with mode: 0644]
test/ELF/relocatable-visibility.s [new file with mode: 0644]
test/ELF/relocatable.s [new file with mode: 0644]
test/ELF/relocation-absolute.s [new file with mode: 0644]
test/ELF/relocation-common.s [new file with mode: 0644]
test/ELF/relocation-copy-alias.s [new file with mode: 0644]
test/ELF/relocation-copy-align-common.s [new file with mode: 0644]
test/ELF/relocation-copy-align.s [new file with mode: 0644]
test/ELF/relocation-copy-flags.s [new file with mode: 0644]
test/ELF/relocation-copy-i686.s [new file with mode: 0644]
test/ELF/relocation-copy-relro.s [new file with mode: 0644]
test/ELF/relocation-copy.s [new file with mode: 0644]
test/ELF/relocation-dtrace.test [new file with mode: 0644]
test/ELF/relocation-group.test [new file with mode: 0644]
test/ELF/relocation-i686.s [new file with mode: 0644]
test/ELF/relocation-in-merge.s [new file with mode: 0644]
test/ELF/relocation-local.s [new file with mode: 0644]
test/ELF/relocation-nocopy.s [new file with mode: 0644]
test/ELF/relocation-non-alloc.s [new file with mode: 0644]
test/ELF/relocation-none-aarch64.test [new file with mode: 0644]
test/ELF/relocation-none-i686.test [new file with mode: 0644]
test/ELF/relocation-past-merge-end.s [new file with mode: 0644]
test/ELF/relocation-relative-absolute.s [new file with mode: 0644]
test/ELF/relocation-relative-synthetic.s [new file with mode: 0644]
test/ELF/relocation-relative-weak.s [new file with mode: 0644]
test/ELF/relocation-shared.s [new file with mode: 0644]
test/ELF/relocation-size-shared.s [new file with mode: 0644]
test/ELF/relocation-size.s [new file with mode: 0644]
test/ELF/relocation-undefined-weak.s [new file with mode: 0644]
test/ELF/relocation.s [new file with mode: 0644]
test/ELF/relro-omagic.s [new file with mode: 0644]
test/ELF/relro-tls.s [new file with mode: 0644]
test/ELF/relro.s [new file with mode: 0644]
test/ELF/reproduce-backslash.s [new file with mode: 0644]
test/ELF/reproduce-error.s [new file with mode: 0644]
test/ELF/reproduce-linkerscript.s [new file with mode: 0644]
test/ELF/reproduce-thin-archive.s [new file with mode: 0644]
test/ELF/reproduce-windows.s [new file with mode: 0644]
test/ELF/reproduce-windows2.s [new file with mode: 0644]
test/ELF/reproduce.s [new file with mode: 0644]
test/ELF/resolution-end.s [new file with mode: 0644]
test/ELF/resolution-shared.s [new file with mode: 0644]
test/ELF/resolution.s [new file with mode: 0644]
test/ELF/retain-symbols-file.s [new file with mode: 0644]
test/ELF/retain-und.s [new file with mode: 0644]
test/ELF/rodynamic.s [new file with mode: 0644]
test/ELF/section-align-0.test [new file with mode: 0644]
test/ELF/section-layout.s [new file with mode: 0644]
test/ELF/section-metadata-err.s [new file with mode: 0644]
test/ELF/section-name.s [new file with mode: 0644]
test/ELF/section-symbol.s [new file with mode: 0644]
test/ELF/section-symbols.test [new file with mode: 0644]
test/ELF/sectionstart-noallochdr.s [new file with mode: 0644]
test/ELF/sectionstart.s [new file with mode: 0644]
test/ELF/segments.s [new file with mode: 0644]
test/ELF/shared-be.s [new file with mode: 0644]
test/ELF/shared.s [new file with mode: 0644]
test/ELF/shf-info-link.test [new file with mode: 0644]
test/ELF/sht-group-gold-r.test [new file with mode: 0644]
test/ELF/soname.s [new file with mode: 0644]
test/ELF/soname2.s [new file with mode: 0644]
test/ELF/sort-norosegment.s [new file with mode: 0644]
test/ELF/splitstacks.s [new file with mode: 0644]
test/ELF/start-lib-comdat.s [new file with mode: 0644]
test/ELF/start-lib.s [new file with mode: 0644]
test/ELF/startstop-gccollect.s [new file with mode: 0644]
test/ELF/startstop-shared.s [new file with mode: 0644]
test/ELF/startstop-shared2.s [new file with mode: 0644]
test/ELF/startstop.s [new file with mode: 0644]
test/ELF/static-with-export-dynamic.s [new file with mode: 0644]
test/ELF/string-gc.s [new file with mode: 0644]
test/ELF/string-table.s [new file with mode: 0644]
test/ELF/strip-all.s [new file with mode: 0644]
test/ELF/strip-debug.s [new file with mode: 0644]
test/ELF/symbol-ordering-file.s [new file with mode: 0644]
test/ELF/symbol-override.s [new file with mode: 0644]
test/ELF/symbols.s [new file with mode: 0644]
test/ELF/symver-archive.s [new file with mode: 0644]
test/ELF/synthetic-got.s [new file with mode: 0644]
test/ELF/sysroot.s [new file with mode: 0644]
test/ELF/tail-merge-string-align.s [new file with mode: 0644]
test/ELF/tls-align.s [new file with mode: 0644]
test/ELF/tls-archive.s [new file with mode: 0644]
test/ELF/tls-dynamic-i686.s [new file with mode: 0644]
test/ELF/tls-dynamic.s [new file with mode: 0644]
test/ELF/tls-error.s [new file with mode: 0644]
test/ELF/tls-got-entry.s [new file with mode: 0644]
test/ELF/tls-got.s [new file with mode: 0644]
test/ELF/tls-i686.s [new file with mode: 0644]
test/ELF/tls-in-archive.s [new file with mode: 0644]
test/ELF/tls-initial-exec-local.s [new file with mode: 0644]
test/ELF/tls-mismatch.s [new file with mode: 0644]
test/ELF/tls-offset.s [new file with mode: 0644]
test/ELF/tls-opt-gdie.s [new file with mode: 0644]
test/ELF/tls-opt-gdiele-i686.s [new file with mode: 0644]
test/ELF/tls-opt-i686.s [new file with mode: 0644]
test/ELF/tls-opt-iele-i686-nopic.s [new file with mode: 0644]
test/ELF/tls-opt-local.s [new file with mode: 0644]
test/ELF/tls-opt-no-plt.s [new file with mode: 0644]
test/ELF/tls-opt.s [new file with mode: 0644]
test/ELF/tls-relocatable.s [new file with mode: 0644]
test/ELF/tls-static.s [new file with mode: 0644]
test/ELF/tls-two-relocs.s [new file with mode: 0644]
test/ELF/tls-weak-undef.s [new file with mode: 0644]
test/ELF/tls.s [new file with mode: 0644]
test/ELF/trace-ar.s [new file with mode: 0644]
test/ELF/trace-symbols.s [new file with mode: 0644]
test/ELF/trace.s [new file with mode: 0644]
test/ELF/ttext-tdata-tbss.s [new file with mode: 0644]
test/ELF/undef-shared.s [new file with mode: 0644]
test/ELF/undef-start.s [new file with mode: 0644]
test/ELF/undef-version-script.s [new file with mode: 0644]
test/ELF/undef-with-plt-addr-i686.s [new file with mode: 0644]
test/ELF/undef-with-plt-addr.s [new file with mode: 0644]
test/ELF/undef.s [new file with mode: 0644]
test/ELF/undefined-opt.s [new file with mode: 0644]
test/ELF/undefined-versioned-symbol.s [new file with mode: 0644]
test/ELF/unresolved-symbols.s [new file with mode: 0644]
test/ELF/user_def_init_array_start.s [new file with mode: 0644]
test/ELF/verdef-defaultver.s [new file with mode: 0644]
test/ELF/verdef-dependency.s [new file with mode: 0644]
test/ELF/verdef.s [new file with mode: 0644]
test/ELF/verneed-as-needed-weak.s [new file with mode: 0644]
test/ELF/verneed-local.s [new file with mode: 0644]
test/ELF/verneed.s [new file with mode: 0644]
test/ELF/version-script-anonymous-local.s [new file with mode: 0644]
test/ELF/version-script-complex-wildcards.s [new file with mode: 0644]
test/ELF/version-script-copy-rel.s [new file with mode: 0644]
test/ELF/version-script-err.s [new file with mode: 0644]
test/ELF/version-script-extern-exact.s [new file with mode: 0644]
test/ELF/version-script-extern-wildcards-anon.s [new file with mode: 0644]
test/ELF/version-script-extern-wildcards.s [new file with mode: 0644]
test/ELF/version-script-extern.s [new file with mode: 0644]
test/ELF/version-script-glob.s [new file with mode: 0644]
test/ELF/version-script-hide-so-symbol.s [new file with mode: 0644]
test/ELF/version-script-locals-extern.s [new file with mode: 0644]
test/ELF/version-script-locals.s [new file with mode: 0644]
test/ELF/version-script-missing.s [new file with mode: 0644]
test/ELF/version-script-no-warn.s [new file with mode: 0644]
test/ELF/version-script-no-warn2.s [new file with mode: 0644]
test/ELF/version-script-noundef.s [new file with mode: 0644]
test/ELF/version-script-symver.s [new file with mode: 0644]
test/ELF/version-script-symver2.s [new file with mode: 0644]
test/ELF/version-script-twice.s [new file with mode: 0644]
test/ELF/version-script-undef-version.s [new file with mode: 0644]
test/ELF/version-script-weak.s [new file with mode: 0644]
test/ELF/version-script.s [new file with mode: 0644]
test/ELF/version-symbol-error.s [new file with mode: 0644]
test/ELF/version-undef-sym.s [new file with mode: 0644]
test/ELF/version-use.s [new file with mode: 0644]
test/ELF/version-wildcard.test [new file with mode: 0644]
test/ELF/visibility.s [new file with mode: 0644]
test/ELF/warn-common.s [new file with mode: 0644]
test/ELF/warn-unresolved-symbols-hidden.s [new file with mode: 0644]
test/ELF/warn-unresolved-symbols.s [new file with mode: 0644]
test/ELF/weak-and-strong-undef.s [new file with mode: 0644]
test/ELF/weak-undef-hidden.s [new file with mode: 0644]
test/ELF/weak-undef-shared.s [new file with mode: 0644]
test/ELF/weak-undef.s [new file with mode: 0644]
test/ELF/whole-archive.s [new file with mode: 0644]
test/ELF/wrap-dynamic-undef.s [new file with mode: 0644]
test/ELF/wrap.s [new file with mode: 0644]
test/ELF/writable-merge.s [new file with mode: 0644]
test/ELF/x86-64-dyn-rel-error.s [new file with mode: 0644]
test/ELF/x86-64-dyn-rel-error2.s [new file with mode: 0644]
test/ELF/x86-64-rela.s [new file with mode: 0644]
test/ELF/x86-64-relax-got-abs.s [new file with mode: 0644]
test/ELF/x86-64-relax-offset.s [new file with mode: 0644]
test/ELF/x86-64-reloc-16.s [new file with mode: 0644]
test/ELF/x86-64-reloc-32-fpic.s [new file with mode: 0644]
test/ELF/x86-64-reloc-8.s [new file with mode: 0644]
test/ELF/x86-64-reloc-error.s [new file with mode: 0644]
test/ELF/x86-64-reloc-pc32-fpic.s [new file with mode: 0644]
test/ELF/x86-64-reloc-range.s [new file with mode: 0644]
test/ELF/x86-64-reloc-tpoff32-fpic.s [new file with mode: 0644]
test/ELF/x86-64-tls-gd-got.s [new file with mode: 0644]
test/ELF/x86-64-tls-gd-local.s [new file with mode: 0644]
test/ELF/x86-64-tls-pie.s [new file with mode: 0644]
test/ELF/zdefs.s [new file with mode: 0644]
test/ELF/zstack-size.s [new file with mode: 0644]
test/ELF/ztext-text-notext.s [new file with mode: 0644]
test/Unit/lit.cfg [new file with mode: 0644]
test/Unit/lit.site.cfg.in [new file with mode: 0644]
test/darwin/Inputs/native-and-mach-o.objtxt [new file with mode: 0644]
test/darwin/Inputs/native-and-mach-o2.objtxt [new file with mode: 0644]
test/darwin/cmdline-objc_gc.objtxt [new file with mode: 0644]
test/darwin/cmdline-objc_gc_compaction.objtxt [new file with mode: 0644]
test/darwin/cmdline-objc_gc_only.objtxt [new file with mode: 0644]
test/darwin/native-and-mach-o.objtxt [new file with mode: 0644]
test/lit.cfg [new file with mode: 0644]
test/lit.site.cfg.in [new file with mode: 0644]
test/mach-o/Inputs/DependencyDump.py [new file with mode: 0755]
test/mach-o/Inputs/PIE.yaml [new file with mode: 0644]
test/mach-o/Inputs/arm-interworking.yaml [new file with mode: 0644]
test/mach-o/Inputs/arm-shims.yaml [new file with mode: 0644]
test/mach-o/Inputs/arm64/libSystem.yaml [new file with mode: 0644]
test/mach-o/Inputs/armv7/libSystem.yaml [new file with mode: 0644]
test/mach-o/Inputs/bar.yaml [new file with mode: 0644]
test/mach-o/Inputs/cstring-sections.yaml [new file with mode: 0644]
test/mach-o/Inputs/exported_symbols_list.exp [new file with mode: 0644]
test/mach-o/Inputs/full.filelist [new file with mode: 0644]
test/mach-o/Inputs/got-order.yaml [new file with mode: 0644]
test/mach-o/Inputs/got-order2.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-arm64.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-armv6.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-armv7.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-x86.yaml [new file with mode: 0644]
test/mach-o/Inputs/hello-world-x86_64.yaml [new file with mode: 0644]
test/mach-o/Inputs/hw.raw_bytes [new file with mode: 0644]
test/mach-o/Inputs/interposing-section.yaml [new file with mode: 0644]
test/mach-o/Inputs/lazy-bind-x86_64-2.yaml [new file with mode: 0644]
test/mach-o/Inputs/lazy-bind-x86_64-3.yaml [new file with mode: 0644]
test/mach-o/Inputs/lazy-bind-x86_64.yaml [new file with mode: 0644]
test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib [new file with mode: 0755]
test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a [new file with mode: 0644]
test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o [new file with mode: 0644]
test/mach-o/Inputs/libbar.a [new file with mode: 0644]
test/mach-o/Inputs/libfoo.a [new file with mode: 0644]
test/mach-o/Inputs/linker-as-ld.yaml [new file with mode: 0644]
test/mach-o/Inputs/no-version-min-load-command-object.yaml [new file with mode: 0644]
test/mach-o/Inputs/order_file-basic.order [new file with mode: 0644]
test/mach-o/Inputs/partial.filelist [new file with mode: 0644]
test/mach-o/Inputs/re-exported-dylib-ordinal.yaml [new file with mode: 0644]
test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml [new file with mode: 0644]
test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml [new file with mode: 0644]
test/mach-o/Inputs/swift-version-1.yaml [new file with mode: 0644]
test/mach-o/Inputs/unwind-info-simple-arm64.yaml [new file with mode: 0644]
test/mach-o/Inputs/use-dylib-install-names.yaml [new file with mode: 0644]
test/mach-o/Inputs/use-simple-dylib.yaml [new file with mode: 0644]
test/mach-o/Inputs/write-final-sections.yaml [new file with mode: 0644]
test/mach-o/Inputs/wrong-arch-error.yaml [new file with mode: 0644]
test/mach-o/Inputs/x86/libSystem.yaml [new file with mode: 0644]
test/mach-o/Inputs/x86_64/libSystem.yaml [new file with mode: 0644]
test/mach-o/PIE.yaml [new file with mode: 0644]
test/mach-o/align_text.yaml [new file with mode: 0644]
test/mach-o/arm-interworking-movw.yaml [new file with mode: 0644]
test/mach-o/arm-interworking.yaml [new file with mode: 0644]
test/mach-o/arm-shims.yaml [new file with mode: 0644]
test/mach-o/arm-subsections-via-symbols.yaml [new file with mode: 0644]
test/mach-o/arm64-reloc-negDelta32-fixup.yaml [new file with mode: 0644]
test/mach-o/arm64-relocs-errors-delta64-offset.yaml [new file with mode: 0644]
test/mach-o/arm64-section-order.yaml [new file with mode: 0644]
test/mach-o/bind-opcodes.yaml [new file with mode: 0644]
test/mach-o/cstring-sections.yaml [new file with mode: 0644]
test/mach-o/data-in-code-load-command.yaml [new file with mode: 0644]
test/mach-o/data-only-dylib.yaml [new file with mode: 0644]
test/mach-o/dead-strip-globals.yaml [new file with mode: 0644]
test/mach-o/debug-syms.yaml [new file with mode: 0644]
test/mach-o/demangle.yaml [new file with mode: 0644]
test/mach-o/dependency_info.yaml [new file with mode: 0644]
test/mach-o/do-not-emit-unwind-fde-arm64.yaml [new file with mode: 0644]
test/mach-o/dso_handle.yaml [new file with mode: 0644]
test/mach-o/dylib-install-names.yaml [new file with mode: 0644]
test/mach-o/eh-frame-relocs-arm64.yaml [new file with mode: 0644]
test/mach-o/error-simulator-vs-macosx.yaml [new file with mode: 0644]
test/mach-o/exe-offsets.yaml [new file with mode: 0644]
test/mach-o/exe-segment-overlap.yaml [new file with mode: 0644]
test/mach-o/executable-exports.yaml [new file with mode: 0644]
test/mach-o/export-trie-order.yaml [new file with mode: 0644]
test/mach-o/exported_symbols_list-dylib.yaml [new file with mode: 0644]
test/mach-o/exported_symbols_list-obj.yaml [new file with mode: 0644]
test/mach-o/exported_symbols_list-undef.yaml [new file with mode: 0644]
test/mach-o/fat-archive.yaml [new file with mode: 0644]
test/mach-o/filelist.yaml [new file with mode: 0644]
test/mach-o/flat_namespace_undef_error.yaml [new file with mode: 0644]
test/mach-o/flat_namespace_undef_suppress.yaml [new file with mode: 0644]
test/mach-o/force_load-dylib.yaml [new file with mode: 0644]
test/mach-o/force_load-x86_64.yaml [new file with mode: 0644]
test/mach-o/framework-user-paths.yaml [new file with mode: 0644]
test/mach-o/function-starts-load-command.yaml [new file with mode: 0644]
test/mach-o/gcc_except_tab-got-arm64.yaml [new file with mode: 0644]
test/mach-o/got-order.yaml [new file with mode: 0644]
test/mach-o/hello-world-arm64.yaml [new file with mode: 0644]
test/mach-o/hello-world-armv6.yaml [new file with mode: 0644]
test/mach-o/hello-world-armv7.yaml [new file with mode: 0644]
test/mach-o/hello-world-x86.yaml [new file with mode: 0644]
test/mach-o/hello-world-x86_64.yaml [new file with mode: 0644]
test/mach-o/image-base.yaml [new file with mode: 0644]
test/mach-o/infer-arch.yaml [new file with mode: 0644]
test/mach-o/interposing-section.yaml [new file with mode: 0644]
test/mach-o/keep_private_externs.yaml [new file with mode: 0644]
test/mach-o/lazy-bind-x86_64.yaml [new file with mode: 0644]
test/mach-o/lc_segment_filesize.yaml [new file with mode: 0644]
test/mach-o/lib-search-paths.yaml [new file with mode: 0644]
test/mach-o/library-order.yaml [new file with mode: 0644]
test/mach-o/library-rescan.yaml [new file with mode: 0644]
test/mach-o/libresolve-bizarre-root-override.yaml [new file with mode: 0644]
test/mach-o/libresolve-multiple-syslibroots.yaml [new file with mode: 0644]
test/mach-o/libresolve-one-syslibroot.yaml [new file with mode: 0644]
test/mach-o/libresolve-simple.yaml [new file with mode: 0644]
test/mach-o/libresolve-user-paths.yaml [new file with mode: 0644]
test/mach-o/libresolve-z.yaml [new file with mode: 0644]
test/mach-o/linker-as-ld.yaml [new file with mode: 0644]
test/mach-o/lit.local.cfg [new file with mode: 0644]
test/mach-o/mach_header-cpusubtype.yaml [new file with mode: 0644]
test/mach-o/mh_bundle_header.yaml [new file with mode: 0644]
test/mach-o/mh_dylib_header.yaml [new file with mode: 0644]
test/mach-o/objc-category-list-atom.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-host-vs-simulator.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-invalid-size.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-invalid-version.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-mismatched-swift-version.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-pass-output.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-simulator-vs-host.yaml [new file with mode: 0644]
test/mach-o/objc-image-info-unsupported-gc.yaml [new file with mode: 0644]
test/mach-o/objc_export_list.yaml [new file with mode: 0644]
test/mach-o/order_file-basic.yaml [new file with mode: 0644]
test/mach-o/parse-aliases.yaml [new file with mode: 0644]
test/mach-o/parse-arm-relocs.yaml [new file with mode: 0644]
test/mach-o/parse-cfstring32.yaml [new file with mode: 0644]
test/mach-o/parse-cfstring64.yaml [new file with mode: 0644]
test/mach-o/parse-compact-unwind32.yaml [new file with mode: 0644]
test/mach-o/parse-compact-unwind64.yaml [new file with mode: 0644]
test/mach-o/parse-data-in-code-armv7.yaml [new file with mode: 0644]
test/mach-o/parse-data-in-code-x86.yaml [new file with mode: 0644]
test/mach-o/parse-data-relocs-arm64.yaml [new file with mode: 0644]
test/mach-o/parse-data-relocs-x86_64.yaml [new file with mode: 0644]
test/mach-o/parse-data.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame-relocs-x86_64.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame-x86-anon.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame-x86-labeled.yaml [new file with mode: 0644]
test/mach-o/parse-eh-frame.yaml [new file with mode: 0644]
test/mach-o/parse-function.yaml [new file with mode: 0644]
test/mach-o/parse-initializers32.yaml [new file with mode: 0644]
test/mach-o/parse-initializers64.yaml [new file with mode: 0644]
test/mach-o/parse-literals-error.yaml [new file with mode: 0644]
test/mach-o/parse-literals.yaml [new file with mode: 0644]
test/mach-o/parse-non-lazy-pointers.yaml [new file with mode: 0644]
test/mach-o/parse-relocs-x86.yaml [new file with mode: 0644]
test/mach-o/parse-section-no-symbol.yaml [new file with mode: 0644]
test/mach-o/parse-tentative-defs.yaml [new file with mode: 0644]
test/mach-o/parse-text-relocs-arm64.yaml [new file with mode: 0644]
test/mach-o/parse-text-relocs-x86_64.yaml [new file with mode: 0644]
test/mach-o/parse-tlv-relocs-x86-64.yaml [new file with mode: 0644]
test/mach-o/re-exported-dylib-ordinal.yaml [new file with mode: 0644]
test/mach-o/rpath.yaml [new file with mode: 0644]
test/mach-o/run-tlv-pass-x86-64.yaml [new file with mode: 0644]
test/mach-o/sdk-version-error.yaml [new file with mode: 0644]
test/mach-o/sectalign.yaml [new file with mode: 0644]
test/mach-o/sectattrs.yaml [new file with mode: 0644]
test/mach-o/sectcreate.yaml [new file with mode: 0644]
test/mach-o/seg-protection-arm64.yaml [new file with mode: 0644]
test/mach-o/seg-protection-x86_64.yaml [new file with mode: 0644]
test/mach-o/source-version.yaml [new file with mode: 0644]
test/mach-o/stack-size.yaml [new file with mode: 0644]
test/mach-o/string-table.yaml [new file with mode: 0644]
test/mach-o/subsections-via-symbols-default.yaml [new file with mode: 0644]
test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml [new file with mode: 0644]
test/mach-o/twolevel_namespace_undef_warning_suppress.yaml [new file with mode: 0644]
test/mach-o/unwind-info-simple-arm64.yaml [new file with mode: 0644]
test/mach-o/unwind-info-simple-x86_64.yaml [new file with mode: 0644]
test/mach-o/upward-dylib-load-command.yaml [new file with mode: 0644]
test/mach-o/upward-dylib-paths.yaml [new file with mode: 0644]
test/mach-o/usage.yaml [new file with mode: 0644]
test/mach-o/use-dylib.yaml [new file with mode: 0644]
test/mach-o/use-simple-dylib.yaml [new file with mode: 0644]
test/mach-o/version-min-load-command-object.yaml [new file with mode: 0644]
test/mach-o/version-min-load-command.yaml [new file with mode: 0644]
test/mach-o/write-final-sections.yaml [new file with mode: 0644]
test/mach-o/wrong-arch-error.yaml [new file with mode: 0644]
tools/lld/CMakeLists.txt [new file with mode: 0644]
tools/lld/lld.cpp [new file with mode: 0644]
unittests/CMakeLists.txt [new file with mode: 0644]
unittests/DriverTests/CMakeLists.txt [new file with mode: 0644]
unittests/DriverTests/DarwinLdDriverTest.cpp [new file with mode: 0644]
unittests/MachOTests/CMakeLists.txt [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp [new file with mode: 0644]
unittests/MachOTests/MachONormalizedFileYAMLTests.cpp [new file with mode: 0644]
unittests/MachOTests/empty_obj_x86_armv7.txt [new file with mode: 0644]

diff --git a/.arcconfig b/.arcconfig
new file mode 100644 (file)
index 0000000..ebf4a4a
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "project_id" : "lld",
+  "conduit_uri" : "https://reviews.llvm.org/"
+}
diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..9b3aa8b
--- /dev/null
@@ -0,0 +1 @@
+BasedOnStyle: LLVM
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0a288ee
--- /dev/null
@@ -0,0 +1,24 @@
+#==============================================================================#
+# This file specifies intentionally untracked files that git should ignore.
+# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
+#==============================================================================#
+
+#==============================================================================#
+# File extensions to be ignored anywhere in the tree.
+#==============================================================================#
+# Temp files created by most text editors.
+*~
+# Merge files created by git.
+*.orig
+# Byte compiled python modules.
+*.pyc
+# vim swap files
+.*.swp
+# Mac OS X Finder layout info
+.DS_Store
+
+#==============================================================================#
+# Directories to be ignored.
+#==============================================================================#
+# Sphinx build files.
+docs/_build
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e2ab0e3
--- /dev/null
@@ -0,0 +1,224 @@
+# Check if lld is built as a standalone project.
+if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+  project(lld)
+  cmake_minimum_required(VERSION 3.4.3)
+
+  set(CMAKE_INCLUDE_CURRENT_DIR ON)
+  set(LLD_BUILT_STANDALONE TRUE)
+
+  find_program(LLVM_CONFIG_PATH "llvm-config" DOC "Path to llvm-config binary")
+  if(NOT LLVM_CONFIG_PATH)
+    message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
+  endif()
+
+  execute_process(COMMAND "${LLVM_CONFIG_PATH}"
+                          "--obj-root"
+                          "--includedir"
+                          "--cmakedir"
+                          "--src-root"
+                  RESULT_VARIABLE HAD_ERROR
+                  OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT
+                  OUTPUT_STRIP_TRAILING_WHITESPACE)
+  if(HAD_ERROR)
+    message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
+  endif()
+
+  string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" LLVM_CONFIG_OUTPUT "${LLVM_CONFIG_OUTPUT}")
+
+  list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT)
+  list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR)
+  list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH)
+  list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR)
+
+  set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree")
+  set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include")
+  set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
+
+  file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR)
+
+  if(NOT EXISTS "${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
+    message(FATAL_ERROR "LLVMConfig.cmake not found")
+  endif()
+  include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
+
+  list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
+
+  set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
+  include_directories("${LLVM_BINARY_DIR}/include" ${LLVM_INCLUDE_DIRS})
+  link_directories(${LLVM_LIBRARY_DIRS})
+
+  set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
+  find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH)
+
+  include(AddLLVM)
+  include(TableGen)
+  include(HandleLLVMOptions)
+
+  if(LLVM_INCLUDE_TESTS)
+    set(Python_ADDITIONAL_VERSIONS 2.7)
+    include(FindPythonInterp)
+    if(NOT PYTHONINTERP_FOUND)
+      message(FATAL_ERROR
+"Unable to find Python interpreter, required for testing.
+
+Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
+    endif()
+
+    if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7)
+      message(FATAL_ERROR "Python 2.7 or newer is required")
+    endif()
+
+    # Check prebuilt llvm/utils.
+    if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
+        AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX})
+      set(LLVM_UTILS_PROVIDED ON)
+    endif()
+
+    if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+      # Note: path not really used, except for checking if lit was found
+      set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+      if(NOT LLVM_UTILS_PROVIDED)
+        add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
+        add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not)
+        set(LLVM_UTILS_PROVIDED ON)
+        set(LLD_TEST_DEPS FileCheck not)
+      endif()
+      set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest)
+      if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h
+          AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
+          AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt)
+        add_subdirectory(${UNITTEST_DIR} utils/unittest)
+      endif()
+    else()
+      # Seek installed Lit.
+      find_program(LLVM_LIT
+                   NAMES llvm-lit lit.py lit
+                   PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit"
+                   DOC "Path to lit.py")
+    endif()
+
+    if(LLVM_LIT)
+      # Define the default arguments to use with 'lit', and an option for the user
+      # to override.
+      set(LIT_ARGS_DEFAULT "-sv")
+      if (MSVC OR XCODE)
+        set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+      endif()
+      set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
+
+      # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
+      if(WIN32 AND NOT CYGWIN)
+        set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
+      endif()
+    else()
+      set(LLVM_INCLUDE_TESTS OFF)
+    endif()
+  endif()
+endif()
+
+set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(LLD_INCLUDE_DIR ${LLD_SOURCE_DIR}/include )
+set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+# Compute the LLD version from the LLVM version.
+string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLD_VERSION
+  ${PACKAGE_VERSION})
+message(STATUS "LLD version: ${LLD_VERSION}")
+
+string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" LLD_VERSION_MAJOR
+  ${LLD_VERSION})
+string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" LLD_VERSION_MINOR
+  ${LLD_VERSION})
+
+# Determine LLD revision and repository.
+# TODO: Figure out a way to get the revision and the repository on windows.
+if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" )
+  execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLD_SOURCE_DIR}
+                  OUTPUT_VARIABLE LLD_REVISION)
+
+  execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLD_SOURCE_DIR}
+                  OUTPUT_VARIABLE LLD_REPOSITORY)
+  if ( LLD_REPOSITORY )
+    # Replace newline characters with spaces
+    string(REGEX REPLACE "(\r?\n)+" " " LLD_REPOSITORY ${LLD_REPOSITORY})
+    # Remove leading spaces
+    STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REPOSITORY "${LLD_REPOSITORY}" )
+    # Remove trailing spaces
+    string(REGEX REPLACE "(\ )+$" "" LLD_REPOSITORY ${LLD_REPOSITORY})
+  endif()
+
+  if ( LLD_REVISION )
+    # Replace newline characters with spaces
+    string(REGEX REPLACE "(\r?\n)+" " " LLD_REVISION ${LLD_REVISION})
+    # Remove leading spaces
+    STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REVISION "${LLD_REVISION}" )
+    # Remove trailing spaces
+    string(REGEX REPLACE "(\ )+$" "" LLD_REVISION ${LLD_REVISION})
+  endif()
+endif ()
+
+# Configure the Version.inc file.
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/lld/Config/Version.inc.in
+  ${CMAKE_CURRENT_BINARY_DIR}/include/lld/Config/Version.inc)
+
+
+if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
+  message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite "
+"the makefiles distributed with LLVM. Please create a directory and run cmake "
+"from there, passing the path to this source directory as the last argument. "
+"This process created the file `CMakeCache.txt' and the directory "
+"`CMakeFiles'. Please delete them.")
+endif()
+
+list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules")
+
+include(AddLLD)
+
+option(LLD_USE_VTUNE
+       "Enable VTune user task tracking."
+       OFF)
+if (LLD_USE_VTUNE)
+  find_package(VTune)
+  if (VTUNE_FOUND)
+    include_directories(${VTune_INCLUDE_DIRS})
+    list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES})
+    add_definitions(-DLLD_HAS_VTUNE)
+  endif()
+endif()
+
+option(LLD_BUILD_TOOLS
+  "Build the lld tools. If OFF, just generate build targets." ON)
+
+if (MSVC)
+  add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.'
+  add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header.
+endif()
+
+include_directories(BEFORE
+  ${CMAKE_CURRENT_BINARY_DIR}/include
+  ${CMAKE_CURRENT_SOURCE_DIR}/include
+  )
+
+if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+  install(DIRECTORY include/
+    DESTINATION include
+    FILES_MATCHING
+    PATTERN "*.h"
+    PATTERN ".svn" EXCLUDE
+    )
+endif()
+
+add_subdirectory(lib)
+add_subdirectory(tools/lld)
+
+if (LLVM_INCLUDE_TESTS)
+  add_subdirectory(test)
+  add_subdirectory(unittests)
+endif()
+
+add_subdirectory(docs)
+add_subdirectory(COFF)
+add_subdirectory(ELF)
+
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
new file mode 100644 (file)
index 0000000..292967e
--- /dev/null
@@ -0,0 +1,19 @@
+This file is a list of the people responsible for ensuring that patches for a
+particular part of LLD are reviewed, either by themself or by someone else.
+They are also the gatekeepers for their part of LLD, with the final word on
+what goes in or not.
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts.  The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S). Each entry should contain at least the (N), (E) and (D) fields.
+
+
+N: Rui Ueyama
+E: ruiu@google.com
+D: COFF, ELF backends (COFF/* ELF/*)
+
+N: Lang Hames, Nick Kledzik
+E: lhames@gmail.com, kledzik@apple.com
+D: Mach-O backend
+
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e565934
--- /dev/null
@@ -0,0 +1,50 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(COFFOptionsTableGen)
+
+if(NOT LLD_BUILT_STANDALONE)
+  set(tablegen_deps intrinsics_gen)
+endif()
+
+add_lld_library(lldCOFF
+  Chunks.cpp
+  DLL.cpp
+  Driver.cpp
+  DriverUtils.cpp
+  Error.cpp
+  ICF.cpp
+  InputFiles.cpp
+  LTO.cpp
+  MapFile.cpp
+  MarkLive.cpp
+  PDB.cpp
+  Strings.cpp
+  SymbolTable.cpp
+  Symbols.cpp
+  Writer.cpp
+
+  LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  BinaryFormat
+  BitReader
+  Core
+  DebugInfoCodeView
+  DebugInfoMSF
+  DebugInfoPDB
+  LTO
+  LibDriver
+  Object
+  MC
+  MCDisassembler
+  Target
+  Option
+  Support
+
+  LINK_LIBS
+  lldCore
+  ${LLVM_PTHREAD_LIB}
+
+  DEPENDS
+  COFFOptionsTableGen
+  ${tablegen_deps}
+  )
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
new file mode 100644 (file)
index 0000000..7d93c28
--- /dev/null
@@ -0,0 +1,500 @@
+//===- Chunks.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::COFF;
+using llvm::support::ulittle32_t;
+
+namespace lld {
+namespace coff {
+
+SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
+    : Chunk(SectionKind), Repl(this), Header(H), File(F),
+      Relocs(File->getCOFFObj()->getRelocations(Header)),
+      NumRelocs(std::distance(Relocs.begin(), Relocs.end())) {
+  // Initialize SectionName.
+  File->getCOFFObj()->getSectionName(Header, SectionName);
+
+  Align = Header->getAlignment();
+
+  // Chunks may be discarded during comdat merging.
+  Discarded = false;
+
+  // If linker GC is disabled, every chunk starts out alive.  If linker GC is
+  // enabled, treat non-comdat sections as roots. Generally optimized object
+  // files will be built with -ffunction-sections or /Gy, so most things worth
+  // stripping will be in a comdat.
+  Live = !Config->DoGC || !isCOMDAT();
+}
+
+static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
+static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
+static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
+static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
+static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); }
+
+static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
+                        OutputSection *OS, uint64_t S) {
+  if (!OS) {
+    if (Sec->isCodeView())
+      return;
+    fatal("SECREL relocation cannot be applied to absolute symbols");
+  }
+  uint64_t SecRel = S - OS->getRVA();
+  assert(SecRel < INT32_MAX && "overflow in SECREL relocation");
+  add32(Off, SecRel);
+}
+
+static void applySecIdx(uint8_t *Off, OutputSection *OS) {
+  // If we have no output section, this must be an absolute symbol. Use the
+  // sentinel absolute symbol section index.
+  uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex;
+  add16(Off, SecIdx);
+}
+
+void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
+                               uint64_t S, uint64_t P) const {
+  switch (Type) {
+  case IMAGE_REL_AMD64_ADDR32:   add32(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_AMD64_ADDR64:   add64(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break;
+  case IMAGE_REL_AMD64_REL32:    add32(Off, S - P - 4); break;
+  case IMAGE_REL_AMD64_REL32_1:  add32(Off, S - P - 5); break;
+  case IMAGE_REL_AMD64_REL32_2:  add32(Off, S - P - 6); break;
+  case IMAGE_REL_AMD64_REL32_3:  add32(Off, S - P - 7); break;
+  case IMAGE_REL_AMD64_REL32_4:  add32(Off, S - P - 8); break;
+  case IMAGE_REL_AMD64_REL32_5:  add32(Off, S - P - 9); break;
+  case IMAGE_REL_AMD64_SECTION:  applySecIdx(Off, OS); break;
+  case IMAGE_REL_AMD64_SECREL:   applySecRel(this, Off, OS, S); break;
+  default:
+    fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+  }
+}
+
+void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS,
+                               uint64_t S, uint64_t P) const {
+  switch (Type) {
+  case IMAGE_REL_I386_ABSOLUTE: break;
+  case IMAGE_REL_I386_DIR32:    add32(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_I386_DIR32NB:  add32(Off, S); break;
+  case IMAGE_REL_I386_REL32:    add32(Off, S - P - 4); break;
+  case IMAGE_REL_I386_SECTION:  applySecIdx(Off, OS); break;
+  case IMAGE_REL_I386_SECREL:   applySecRel(this, Off, OS, S); break;
+  default:
+    fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+  }
+}
+
+static void applyMOV(uint8_t *Off, uint16_t V) {
+  write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf));
+  write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff));
+}
+
+static uint16_t readMOV(uint8_t *Off) {
+  uint16_t Opcode1 = read16le(Off);
+  uint16_t Opcode2 = read16le(Off + 2);
+  uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700);
+  Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12);
+  return Imm;
+}
+
+static void applyMOV32T(uint8_t *Off, uint32_t V) {
+  uint16_t ImmW = readMOV(Off);     // read MOVW operand
+  uint16_t ImmT = readMOV(Off + 4); // read MOVT operand
+  uint32_t Imm = ImmW | (ImmT << 16);
+  V += Imm;                         // add the immediate offset
+  applyMOV(Off, V);           // set MOVW operand
+  applyMOV(Off + 4, V >> 16); // set MOVT operand
+}
+
+static void applyBranch20T(uint8_t *Off, int32_t V) {
+  uint32_t S = V < 0 ? 1 : 0;
+  uint32_t J1 = (V >> 19) & 1;
+  uint32_t J2 = (V >> 18) & 1;
+  or16(Off, (S << 10) | ((V >> 12) & 0x3f));
+  or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+static void applyBranch24T(uint8_t *Off, int32_t V) {
+  if (!isInt<25>(V))
+    fatal("relocation out of range");
+  uint32_t S = V < 0 ? 1 : 0;
+  uint32_t J1 = ((~V >> 23) & 1) ^ S;
+  uint32_t J2 = ((~V >> 22) & 1) ^ S;
+  or16(Off, (S << 10) | ((V >> 12) & 0x3ff));
+  // Clear out the J1 and J2 bits which may be set.
+  write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
+                               uint64_t S, uint64_t P) const {
+  // Pointer to thumb code must have the LSB set.
+  uint64_t SX = S;
+  if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+    SX |= 1;
+  switch (Type) {
+  case IMAGE_REL_ARM_ADDR32:    add32(Off, SX + Config->ImageBase); break;
+  case IMAGE_REL_ARM_ADDR32NB:  add32(Off, SX); break;
+  case IMAGE_REL_ARM_MOV32T:    applyMOV32T(Off, SX + Config->ImageBase); break;
+  case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break;
+  case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break;
+  case IMAGE_REL_ARM_BLX23T:    applyBranch24T(Off, SX - P - 4); break;
+  case IMAGE_REL_ARM_SECTION:   applySecIdx(Off, OS); break;
+  case IMAGE_REL_ARM_SECREL:    applySecRel(this, Off, OS, S); break;
+  default:
+    fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+  }
+}
+
+static void applyArm64Addr(uint8_t *Off, uint64_t Imm) {
+  uint32_t ImmLo = (Imm & 0x3) << 29;
+  uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
+  uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
+  write32le(Off, (read32le(Off) & ~Mask) | ImmLo | ImmHi);
+}
+
+// Update the immediate field in a AARCH64 ldr, str, and add instruction.
+static void applyArm64Imm(uint8_t *Off, uint64_t Imm) {
+  uint32_t Orig = read32le(Off);
+  Imm += (Orig >> 10) & 0xFFF;
+  Orig &= ~(0xFFF << 10);
+  write32le(Off, Orig | ((Imm & 0xFFF) << 10));
+}
+
+static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
+  int Size = read32le(Off) >> 30;
+  Imm >>= Size;
+  applyArm64Imm(Off, Imm);
+}
+
+void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
+                                 uint64_t S, uint64_t P) const {
+  switch (Type) {
+  case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, (S >> 12) - (P >> 12)); break;
+  case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff); break;
+  case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
+  case IMAGE_REL_ARM64_BRANCH26:       or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break;
+  case IMAGE_REL_ARM64_ADDR32:         add32(Off, S + Config->ImageBase); break;
+  case IMAGE_REL_ARM64_ADDR64:         add64(Off, S + Config->ImageBase); break;
+  default:
+    fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+  }
+}
+
+void SectionChunk::writeTo(uint8_t *Buf) const {
+  if (!hasData())
+    return;
+  // Copy section contents from source object file to output file.
+  ArrayRef<uint8_t> A = getContents();
+  memcpy(Buf + OutputSectionOff, A.data(), A.size());
+
+  // Apply relocations.
+  size_t InputSize = getSize();
+  for (const coff_relocation &Rel : Relocs) {
+    // Check for an invalid relocation offset. This check isn't perfect, because
+    // we don't have the relocation size, which is only known after checking the
+    // machine and relocation type. As a result, a relocation may overwrite the
+    // beginning of the following input section.
+    if (Rel.VirtualAddress >= InputSize)
+      fatal("relocation points beyond the end of its parent section");
+
+    uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
+
+    // Get the output section of the symbol for this relocation.  The output
+    // section is needed to compute SECREL and SECTION relocations used in debug
+    // info.
+    SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex);
+    Defined *Sym = cast<Defined>(Body);
+    Chunk *C = Sym->getChunk();
+    OutputSection *OS = C ? C->getOutputSection() : nullptr;
+
+    // Only absolute and __ImageBase symbols lack an output section. For any
+    // other symbol, this indicates that the chunk was discarded.  Normally
+    // relocations against discarded sections are an error.  However, debug info
+    // sections are not GC roots and can end up with these kinds of relocations.
+    // Skip these relocations.
+    if (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym)) {
+      if (isCodeView() || isDWARF())
+        continue;
+      fatal("relocation against symbol in discarded section: " +
+            Sym->getName());
+    }
+    uint64_t S = Sym->getRVA();
+
+    // Compute the RVA of the relocation for relative relocations.
+    uint64_t P = RVA + Rel.VirtualAddress;
+    switch (Config->Machine) {
+    case AMD64:
+      applyRelX64(Off, Rel.Type, OS, S, P);
+      break;
+    case I386:
+      applyRelX86(Off, Rel.Type, OS, S, P);
+      break;
+    case ARMNT:
+      applyRelARM(Off, Rel.Type, OS, S, P);
+      break;
+    case ARM64:
+      applyRelARM64(Off, Rel.Type, OS, S, P);
+      break;
+    default:
+      llvm_unreachable("unknown machine type");
+    }
+  }
+}
+
+void SectionChunk::addAssociative(SectionChunk *Child) {
+  AssocChildren.push_back(Child);
+}
+
+static uint8_t getBaserelType(const coff_relocation &Rel) {
+  switch (Config->Machine) {
+  case AMD64:
+    if (Rel.Type == IMAGE_REL_AMD64_ADDR64)
+      return IMAGE_REL_BASED_DIR64;
+    return IMAGE_REL_BASED_ABSOLUTE;
+  case I386:
+    if (Rel.Type == IMAGE_REL_I386_DIR32)
+      return IMAGE_REL_BASED_HIGHLOW;
+    return IMAGE_REL_BASED_ABSOLUTE;
+  case ARMNT:
+    if (Rel.Type == IMAGE_REL_ARM_ADDR32)
+      return IMAGE_REL_BASED_HIGHLOW;
+    if (Rel.Type == IMAGE_REL_ARM_MOV32T)
+      return IMAGE_REL_BASED_ARM_MOV32T;
+    return IMAGE_REL_BASED_ABSOLUTE;
+  case ARM64:
+    if (Rel.Type == IMAGE_REL_ARM64_ADDR64)
+      return IMAGE_REL_BASED_DIR64;
+    return IMAGE_REL_BASED_ABSOLUTE;
+  default:
+    llvm_unreachable("unknown machine type");
+  }
+}
+
+// Windows-specific.
+// Collect all locations that contain absolute addresses, which need to be
+// fixed by the loader if load-time relocation is needed.
+// Only called when base relocation is enabled.
+void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
+  for (const coff_relocation &Rel : Relocs) {
+    uint8_t Ty = getBaserelType(Rel);
+    if (Ty == IMAGE_REL_BASED_ABSOLUTE)
+      continue;
+    SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex);
+    if (isa<DefinedAbsolute>(Body))
+      continue;
+    Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
+  }
+}
+
+bool SectionChunk::hasData() const {
+  return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+}
+
+uint32_t SectionChunk::getPermissions() const {
+  return Header->Characteristics & PermMask;
+}
+
+bool SectionChunk::isCOMDAT() const {
+  return Header->Characteristics & IMAGE_SCN_LNK_COMDAT;
+}
+
+void SectionChunk::printDiscardedMessage() const {
+  // Removed by dead-stripping. If it's removed by ICF, ICF already
+  // printed out the name, so don't repeat that here.
+  if (Sym && this == Repl) {
+    if (Discarded)
+      message("Discarded comdat symbol " + Sym->getName());
+    else if (!Live)
+      message("Discarded " + Sym->getName());
+  }
+}
+
+StringRef SectionChunk::getDebugName() {
+  if (Sym)
+    return Sym->getName();
+  return "";
+}
+
+ArrayRef<uint8_t> SectionChunk::getContents() const {
+  ArrayRef<uint8_t> A;
+  File->getCOFFObj()->getSectionContents(Header, A);
+  return A;
+}
+
+void SectionChunk::replace(SectionChunk *Other) {
+  Other->Repl = Repl;
+  Other->Live = false;
+}
+
+CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
+  // Common symbols are aligned on natural boundaries up to 32 bytes.
+  // This is what MSVC link.exe does.
+  Align = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue()));
+}
+
+uint32_t CommonChunk::getPermissions() const {
+  return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
+         IMAGE_SCN_MEM_WRITE;
+}
+
+void StringChunk::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, Str.data(), Str.size());
+}
+
+ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) {
+  // Intel Optimization Manual says that all branch targets
+  // should be 16-byte aligned. MSVC linker does this too.
+  Align = 16;
+}
+
+void ImportThunkChunkX64::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+  // The first two bytes is a JMP instruction. Fill its operand.
+  write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize());
+}
+
+void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) {
+  Res->emplace_back(getRVA() + 2);
+}
+
+void ImportThunkChunkX86::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+  // The first two bytes is a JMP instruction. Fill its operand.
+  write32le(Buf + OutputSectionOff + 2,
+            ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) {
+  Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T);
+}
+
+void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM));
+  // Fix mov.w and mov.t operands.
+  applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
+  int64_t PageOff = (ImpSymbol->getRVA() >> 12) - (RVA >> 12);
+  int64_t Off = ImpSymbol->getRVA() & 0xfff;
+  memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
+  applyArm64Addr(Buf + OutputSectionOff, PageOff);
+  applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
+}
+
+void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
+  Res->emplace_back(getRVA());
+}
+
+size_t LocalImportChunk::getSize() const {
+  return Config->is64() ? 8 : 4;
+}
+
+void LocalImportChunk::writeTo(uint8_t *Buf) const {
+  if (Config->is64()) {
+    write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
+  } else {
+    write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
+  }
+}
+
+void SEHTableChunk::writeTo(uint8_t *Buf) const {
+  ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
+  size_t Cnt = 0;
+  for (Defined *D : Syms)
+    Begin[Cnt++] = D->getRVA();
+  std::sort(Begin, Begin + Cnt);
+}
+
+// Windows-specific. This class represents a block in .reloc section.
+// The format is described here.
+//
+// On Windows, each DLL is linked against a fixed base address and
+// usually loaded to that address. However, if there's already another
+// DLL that overlaps, the loader has to relocate it. To do that, DLLs
+// contain .reloc sections which contain offsets that need to be fixed
+// up at runtime. If the loader finds that a DLL cannot be loaded to its
+// desired base address, it loads it to somewhere else, and add <actual
+// base address> - <desired base address> to each offset that is
+// specified by the .reloc section. In ELF terms, .reloc sections
+// contain relative relocations in REL format (as opposed to RELA.)
+//
+// This already significantly reduces the size of relocations compared
+// to ELF .rel.dyn, but Windows does more to reduce it (probably because
+// it was invented for PCs in the late '80s or early '90s.)  Offsets in
+// .reloc are grouped by page where the page size is 12 bits, and
+// offsets sharing the same page address are stored consecutively to
+// represent them with less space. This is very similar to the page
+// table which is grouped by (multiple stages of) pages.
+//
+// For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00,
+// 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4
+// bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they
+// are represented like this:
+//
+//   0x00000  -- page address (4 bytes)
+//   16       -- size of this block (4 bytes)
+//     0xA030 -- entries (2 bytes each)
+//     0xA500
+//     0xA700
+//     0xAA00
+//   0x20000  -- page address (4 bytes)
+//   12       -- size of this block (4 bytes)
+//     0xA004 -- entries (2 bytes each)
+//     0xA008
+//
+// Usually we have a lot of relocations for each page, so the number of
+// bytes for one .reloc entry is close to 2 bytes on average.
+BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
+  // Block header consists of 4 byte page RVA and 4 byte block size.
+  // Each entry is 2 byte. Last entry may be padding.
+  Data.resize(alignTo((End - Begin) * 2 + 8, 4));
+  uint8_t *P = Data.data();
+  write32le(P, Page);
+  write32le(P + 4, Data.size());
+  P += 8;
+  for (Baserel *I = Begin; I != End; ++I) {
+    write16le(P, (I->Type << 12) | (I->RVA - Page));
+    P += 2;
+  }
+}
+
+void BaserelChunk::writeTo(uint8_t *Buf) const {
+  memcpy(Buf + OutputSectionOff, Data.data(), Data.size());
+}
+
+uint8_t Baserel::getDefaultType() {
+  switch (Config->Machine) {
+  case AMD64:
+    return IMAGE_REL_BASED_DIR64;
+  case I386:
+    return IMAGE_REL_BASED_HIGHLOW;
+  default:
+    llvm_unreachable("unknown machine type");
+  }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
new file mode 100644 (file)
index 0000000..ece5419
--- /dev/null
@@ -0,0 +1,375 @@
+//===- Chunks.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_CHUNKS_H
+#define LLD_COFF_CHUNKS_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Object/COFF.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::ImportDirectoryTableEntry;
+using llvm::object::COFFSymbolRef;
+using llvm::object::SectionRef;
+using llvm::object::coff_relocation;
+using llvm::object::coff_section;
+
+class Baserel;
+class Defined;
+class DefinedImportData;
+class DefinedRegular;
+class ObjectFile;
+class OutputSection;
+class SymbolBody;
+
+// Mask for section types (code, data, bss, disacardable, etc.)
+// and permissions (writable, readable or executable).
+const uint32_t PermMask = 0xFF0000F0;
+
+// A Chunk represents a chunk of data that will occupy space in the
+// output (if the resolver chose that). It may or may not be backed by
+// a section of an input file. It could be linker-created data, or
+// doesn't even have actual data (if common or bss).
+class Chunk {
+public:
+  enum Kind { SectionKind, OtherKind };
+  Kind kind() const { return ChunkKind; }
+  virtual ~Chunk() = default;
+
+  // Returns the size of this chunk (even if this is a common or BSS.)
+  virtual size_t getSize() const = 0;
+
+  // Write this chunk to a mmap'ed file, assuming Buf is pointing to
+  // beginning of the file. Because this function may use RVA values
+  // of other chunks for relocations, you need to set them properly
+  // before calling this function.
+  virtual void writeTo(uint8_t *Buf) const {}
+
+  // The writer sets and uses the addresses.
+  uint64_t getRVA() const { return RVA; }
+  uint32_t getAlign() const { return Align; }
+  void setRVA(uint64_t V) { RVA = V; }
+
+  // Returns true if this has non-zero data. BSS chunks return
+  // false. If false is returned, the space occupied by this chunk
+  // will be filled with zeros.
+  virtual bool hasData() const { return true; }
+
+  // Returns readable/writable/executable bits.
+  virtual uint32_t getPermissions() const { return 0; }
+
+  // Returns the section name if this is a section chunk.
+  // It is illegal to call this function on non-section chunks.
+  virtual StringRef getSectionName() const {
+    llvm_unreachable("unimplemented getSectionName");
+  }
+
+  // An output section has pointers to chunks in the section, and each
+  // chunk has a back pointer to an output section.
+  void setOutputSection(OutputSection *O) { Out = O; }
+  OutputSection *getOutputSection() { return Out; }
+
+  // Windows-specific.
+  // Collect all locations that contain absolute addresses for base relocations.
+  virtual void getBaserels(std::vector<Baserel> *Res) {}
+
+  // Returns a human-readable name of this chunk. Chunks are unnamed chunks of
+  // bytes, so this is used only for logging or debugging.
+  virtual StringRef getDebugName() { return ""; }
+
+protected:
+  Chunk(Kind K = OtherKind) : ChunkKind(K) {}
+  const Kind ChunkKind;
+
+  // The alignment of this chunk. The writer uses the value.
+  uint32_t Align = 1;
+
+  // The RVA of this chunk in the output. The writer sets a value.
+  uint64_t RVA = 0;
+
+public:
+  // The offset from beginning of the output section. The writer sets a value.
+  uint64_t OutputSectionOff = 0;
+
+protected:
+  // The output section for this chunk.
+  OutputSection *Out = nullptr;
+};
+
+// A chunk corresponding a section of an input file.
+class SectionChunk final : public Chunk {
+  // Identical COMDAT Folding feature accesses section internal data.
+  friend class ICF;
+
+public:
+  class symbol_iterator : public llvm::iterator_adaptor_base<
+                              symbol_iterator, const coff_relocation *,
+                              std::random_access_iterator_tag, SymbolBody *> {
+    friend SectionChunk;
+
+    ObjectFile *File;
+
+    symbol_iterator(ObjectFile *File, const coff_relocation *I)
+        : symbol_iterator::iterator_adaptor_base(I), File(File) {}
+
+  public:
+    symbol_iterator() = default;
+
+    SymbolBody *operator*() const {
+      return File->getSymbolBody(I->SymbolTableIndex);
+    }
+  };
+
+  SectionChunk(ObjectFile *File, const coff_section *Header);
+  static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
+  size_t getSize() const override { return Header->SizeOfRawData; }
+  ArrayRef<uint8_t> getContents() const;
+  void writeTo(uint8_t *Buf) const override;
+  bool hasData() const override;
+  uint32_t getPermissions() const override;
+  StringRef getSectionName() const override { return SectionName; }
+  void getBaserels(std::vector<Baserel> *Res) override;
+  bool isCOMDAT() const;
+  void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+                   uint64_t P) const;
+  void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+                   uint64_t P) const;
+  void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+                   uint64_t P) const;
+  void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+                     uint64_t P) const;
+
+  // Called if the garbage collector decides to not include this chunk
+  // in a final output. It's supposed to print out a log message to stdout.
+  void printDiscardedMessage() const;
+
+  // Adds COMDAT associative sections to this COMDAT section. A chunk
+  // and its children are treated as a group by the garbage collector.
+  void addAssociative(SectionChunk *Child);
+
+  StringRef getDebugName() override;
+  void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; }
+
+  // Returns true if the chunk was not dropped by GC or COMDAT deduplication.
+  bool isLive() { return Live && !Discarded; }
+
+  // Used by the garbage collector.
+  void markLive() {
+    assert(Config->DoGC && "should only mark things live from GC");
+    assert(!isLive() && "Cannot mark an already live section!");
+    Live = true;
+  }
+
+  // Returns true if this chunk was dropped by COMDAT deduplication.
+  bool isDiscarded() const { return Discarded; }
+
+  // Used by the SymbolTable when discarding unused comdat sections. This is
+  // redundant when GC is enabled, as all comdat sections will start out dead.
+  void markDiscarded() { Discarded = true; }
+
+  // True if this is a codeview debug info chunk. These will not be laid out in
+  // the image. Instead they will end up in the PDB, if one is requested.
+  bool isCodeView() const {
+    return SectionName == ".debug" || SectionName.startswith(".debug$");
+  }
+
+  // True if this is a DWARF debug info chunk.
+  bool isDWARF() const { return SectionName.startswith(".debug_"); }
+
+  // Allow iteration over the bodies of this chunk's relocated symbols.
+  llvm::iterator_range<symbol_iterator> symbols() const {
+    return llvm::make_range(symbol_iterator(File, Relocs.begin()),
+                            symbol_iterator(File, Relocs.end()));
+  }
+
+  // Allow iteration over the associated child chunks for this section.
+  ArrayRef<SectionChunk *> children() const { return AssocChildren; }
+
+  // A pointer pointing to a replacement for this chunk.
+  // Initially it points to "this" object. If this chunk is merged
+  // with other chunk by ICF, it points to another chunk,
+  // and this chunk is considrered as dead.
+  SectionChunk *Repl;
+
+  // The CRC of the contents as described in the COFF spec 4.5.5.
+  // Auxiliary Format 5: Section Definitions. Used for ICF.
+  uint32_t Checksum = 0;
+
+  const coff_section *Header;
+
+  // The file that this chunk was created from.
+  ObjectFile *File;
+
+private:
+  StringRef SectionName;
+  std::vector<SectionChunk *> AssocChildren;
+  llvm::iterator_range<const coff_relocation *> Relocs;
+  size_t NumRelocs;
+
+  // True if this chunk was discarded because it was a duplicate comdat section.
+  bool Discarded;
+
+  // Used by the garbage collector.
+  bool Live;
+
+  // Used for ICF (Identical COMDAT Folding)
+  void replace(SectionChunk *Other);
+  uint32_t Class[2] = {0, 0};
+
+  // Sym points to a section symbol if this is a COMDAT chunk.
+  DefinedRegular *Sym = nullptr;
+};
+
+// A chunk for common symbols. Common chunks don't have actual data.
+class CommonChunk : public Chunk {
+public:
+  CommonChunk(const COFFSymbolRef Sym);
+  size_t getSize() const override { return Sym.getValue(); }
+  bool hasData() const override { return false; }
+  uint32_t getPermissions() const override;
+  StringRef getSectionName() const override { return ".bss"; }
+
+private:
+  const COFFSymbolRef Sym;
+};
+
+// A chunk for linker-created strings.
+class StringChunk : public Chunk {
+public:
+  explicit StringChunk(StringRef S) : Str(S) {}
+  size_t getSize() const override { return Str.size() + 1; }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  StringRef Str;
+};
+
+static const uint8_t ImportThunkX86[] = {
+    0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
+};
+
+static const uint8_t ImportThunkARM[] = {
+    0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
+    0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
+    0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
+};
+
+static const uint8_t ImportThunkARM64[] = {
+    0x10, 0x00, 0x00, 0x90, // adrp x16, #0
+    0x10, 0x02, 0x40, 0xf9, // ldr  x16, [x16]
+    0x00, 0x02, 0x1f, 0xd6, // br   x16
+};
+
+// Windows-specific.
+// A chunk for DLL import jump table entry. In a final output, it's
+// contents will be a JMP instruction to some __imp_ symbol.
+class ImportThunkChunkX64 : public Chunk {
+public:
+  explicit ImportThunkChunkX64(Defined *S);
+  size_t getSize() const override { return sizeof(ImportThunkX86); }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *ImpSymbol;
+};
+
+class ImportThunkChunkX86 : public Chunk {
+public:
+  explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {}
+  size_t getSize() const override { return sizeof(ImportThunkX86); }
+  void getBaserels(std::vector<Baserel> *Res) override;
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *ImpSymbol;
+};
+
+class ImportThunkChunkARM : public Chunk {
+public:
+  explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {}
+  size_t getSize() const override { return sizeof(ImportThunkARM); }
+  void getBaserels(std::vector<Baserel> *Res) override;
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *ImpSymbol;
+};
+
+class ImportThunkChunkARM64 : public Chunk {
+public:
+  explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {}
+  size_t getSize() const override { return sizeof(ImportThunkARM64); }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *ImpSymbol;
+};
+
+// Windows-specific.
+// See comments for DefinedLocalImport class.
+class LocalImportChunk : public Chunk {
+public:
+  explicit LocalImportChunk(Defined *S) : Sym(S) {}
+  size_t getSize() const override;
+  void getBaserels(std::vector<Baserel> *Res) override;
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  Defined *Sym;
+};
+
+// Windows-specific.
+// A chunk for SEH table which contains RVAs of safe exception handler
+// functions. x86-only.
+class SEHTableChunk : public Chunk {
+public:
+  explicit SEHTableChunk(std::set<Defined *> S) : Syms(std::move(S)) {}
+  size_t getSize() const override { return Syms.size() * 4; }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  std::set<Defined *> Syms;
+};
+
+// Windows-specific.
+// This class represents a block in .reloc section.
+// See the PE/COFF spec 5.6 for details.
+class BaserelChunk : public Chunk {
+public:
+  BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End);
+  size_t getSize() const override { return Data.size(); }
+  void writeTo(uint8_t *Buf) const override;
+
+private:
+  std::vector<uint8_t> Data;
+};
+
+class Baserel {
+public:
+  Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {}
+  explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {}
+  uint8_t getDefaultType();
+
+  uint32_t RVA;
+  uint8_t Type;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Config.h b/COFF/Config.h
new file mode 100644 (file)
index 0000000..7f8259d
--- /dev/null
@@ -0,0 +1,174 @@
+//===- Config.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_CONFIG_H
+#define LLD_COFF_CONFIG_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::WindowsSubsystem;
+using llvm::StringRef;
+class DefinedAbsolute;
+class DefinedRelative;
+class StringChunk;
+struct Symbol;
+class SymbolBody;
+
+// Short aliases.
+static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64;
+static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
+static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+
+// Represents an /export option.
+struct Export {
+  StringRef Name;       // N in /export:N or /export:E=N
+  StringRef ExtName;    // E in /export:E=N
+  SymbolBody *Sym = nullptr;
+  uint16_t Ordinal = 0;
+  bool Noname = false;
+  bool Data = false;
+  bool Private = false;
+  bool Constant = false;
+
+  // If an export is a form of /export:foo=dllname.bar, that means
+  // that foo should be exported as an alias to bar in the DLL.
+  // ForwardTo is set to "dllname.bar" part. Usually empty.
+  StringRef ForwardTo;
+  StringChunk *ForwardChunk = nullptr;
+
+  // True if this /export option was in .drectves section.
+  bool Directives = false;
+  StringRef SymbolName;
+  StringRef ExportName; // Name in DLL
+
+  bool operator==(const Export &E) {
+    return (Name == E.Name && ExtName == E.ExtName &&
+            Ordinal == E.Ordinal && Noname == E.Noname &&
+            Data == E.Data && Private == E.Private);
+  }
+};
+
+enum class DebugType {
+  None  = 0x0,
+  CV    = 0x1,  /// CodeView
+  PData = 0x2,  /// Procedure Data
+  Fixup = 0x4,  /// Relocation Table
+};
+
+// Global configuration.
+struct Configuration {
+  enum ManifestKind { SideBySide, Embed, No };
+  bool is64() { return Machine == AMD64 || Machine == ARM64; }
+
+  llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
+  bool Verbose = false;
+  WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
+  SymbolBody *Entry = nullptr;
+  bool NoEntry = false;
+  std::string OutputFile;
+  std::string ImportName;
+  bool ColorDiagnostics;
+  bool DoGC = true;
+  bool DoICF = true;
+  uint64_t ErrorLimit = 20;
+  bool Relocatable = true;
+  bool Force = false;
+  bool Debug = false;
+  bool WriteSymtab = true;
+  unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+  llvm::SmallString<128> PDBPath;
+  std::vector<llvm::StringRef> Argv;
+
+  // Symbols in this set are considered as live by the garbage collector.
+  std::set<SymbolBody *> GCRoot;
+
+  std::set<StringRef> NoDefaultLibs;
+  bool NoDefaultLibAll = false;
+
+  // True if we are creating a DLL.
+  bool DLL = false;
+  StringRef Implib;
+  std::vector<Export> Exports;
+  std::set<std::string> DelayLoads;
+  std::map<std::string, int> DLLOrder;
+  SymbolBody *DelayLoadHelper = nullptr;
+
+  bool SaveTemps = false;
+
+  // Used for SafeSEH.
+  Symbol *SEHTable = nullptr;
+  Symbol *SEHCount = nullptr;
+
+  // Used for /opt:lldlto=N
+  unsigned LTOOptLevel = 2;
+
+  // Used for /opt:lldltojobs=N
+  unsigned LTOJobs = 0;
+  // Used for /opt:lldltopartitions=N
+  unsigned LTOPartitions = 1;
+
+  // Used for /merge:from=to (e.g. /merge:.rdata=.text)
+  std::map<StringRef, StringRef> Merge;
+
+  // Used for /section=.name,{DEKPRSW} to set section attributes.
+  std::map<StringRef, uint32_t> Section;
+
+  // Options for manifest files.
+  ManifestKind Manifest = No;
+  int ManifestID = 1;
+  StringRef ManifestDependency;
+  bool ManifestUAC = true;
+  std::vector<std::string> ManifestInput;
+  StringRef ManifestLevel = "'asInvoker'";
+  StringRef ManifestUIAccess = "'false'";
+  StringRef ManifestFile;
+
+  // Used for /failifmismatch.
+  std::map<StringRef, StringRef> MustMatch;
+
+  // Used for /alternatename.
+  std::map<StringRef, StringRef> AlternateNames;
+
+  // Used for /lldmap.
+  std::string MapFile;
+
+  uint64_t ImageBase = -1;
+  uint64_t StackReserve = 1024 * 1024;
+  uint64_t StackCommit = 4096;
+  uint64_t HeapReserve = 1024 * 1024;
+  uint64_t HeapCommit = 4096;
+  uint32_t MajorImageVersion = 0;
+  uint32_t MinorImageVersion = 0;
+  uint32_t MajorOSVersion = 6;
+  uint32_t MinorOSVersion = 0;
+  bool DynamicBase = true;
+  bool NxCompat = true;
+  bool AllowIsolation = true;
+  bool TerminalServerAware = true;
+  bool LargeAddressAware = false;
+  bool HighEntropyVA = false;
+  bool AppContainer = false;
+};
+
+extern Configuration *Config;
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
new file mode 100644 (file)
index 0000000..d76410b
--- /dev/null
@@ -0,0 +1,548 @@
+//===- DLL.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines various types of chunks for the DLL import or export
+// descriptor tables. They are inherently Windows-specific.
+// You need to read Microsoft PE/COFF spec to understand details
+// about the data structures.
+//
+// If you are not particularly interested in linking against Windows
+// DLL, you can skip this file, and you should still be able to
+// understand the rest of the linker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "DLL.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::COFF;
+
+namespace lld {
+namespace coff {
+namespace {
+
+// Import table
+
+static int ptrSize() { return Config->is64() ? 8 : 4; }
+
+// A chunk for the import descriptor table.
+class HintNameChunk : public Chunk {
+public:
+  HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}
+
+  size_t getSize() const override {
+    // Starts with 2 byte Hint field, followed by a null-terminated string,
+    // ends with 0 or 1 byte padding.
+    return alignTo(Name.size() + 3, 2);
+  }
+
+  void writeTo(uint8_t *Buf) const override {
+    write16le(Buf + OutputSectionOff, Hint);
+    memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size());
+  }
+
+private:
+  StringRef Name;
+  uint16_t Hint;
+};
+
+// A chunk for the import descriptor table.
+class LookupChunk : public Chunk {
+public:
+  explicit LookupChunk(Chunk *C) : HintName(C) {}
+  size_t getSize() const override { return ptrSize(); }
+
+  void writeTo(uint8_t *Buf) const override {
+    write32le(Buf + OutputSectionOff, HintName->getRVA());
+  }
+
+  Chunk *HintName;
+};
+
+// A chunk for the import descriptor table.
+// This chunk represent import-by-ordinal symbols.
+// See Microsoft PE/COFF spec 7.1. Import Header for details.
+class OrdinalOnlyChunk : public Chunk {
+public:
+  explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {}
+  size_t getSize() const override { return ptrSize(); }
+
+  void writeTo(uint8_t *Buf) const override {
+    // An import-by-ordinal slot has MSB 1 to indicate that
+    // this is import-by-ordinal (and not import-by-name).
+    if (Config->is64()) {
+      write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal);
+    } else {
+      write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal);
+    }
+  }
+
+  uint16_t Ordinal;
+};
+
+// A chunk for the import descriptor table.
+class ImportDirectoryChunk : public Chunk {
+public:
+  explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
+  size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
+
+  void writeTo(uint8_t *Buf) const override {
+    auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
+    E->ImportLookupTableRVA = LookupTab->getRVA();
+    E->NameRVA = DLLName->getRVA();
+    E->ImportAddressTableRVA = AddressTab->getRVA();
+  }
+
+  Chunk *DLLName;
+  Chunk *LookupTab;
+  Chunk *AddressTab;
+};
+
+// A chunk representing null terminator in the import table.
+// Contents of this chunk is always null bytes.
+class NullChunk : public Chunk {
+public:
+  explicit NullChunk(size_t N) : Size(N) {}
+  bool hasData() const override { return false; }
+  size_t getSize() const override { return Size; }
+  void setAlign(size_t N) { Align = N; }
+
+private:
+  size_t Size;
+};
+
+static std::vector<std::vector<DefinedImportData *>>
+binImports(const std::vector<DefinedImportData *> &Imports) {
+  // Group DLL-imported symbols by DLL name because that's how
+  // symbols are layed out in the import descriptor table.
+  auto Less = [](const std::string &A, const std::string &B) {
+    return Config->DLLOrder[A] < Config->DLLOrder[B];
+  };
+  std::map<std::string, std::vector<DefinedImportData *>,
+           bool(*)(const std::string &, const std::string &)> M(Less);
+  for (DefinedImportData *Sym : Imports)
+    M[Sym->getDLLName().lower()].push_back(Sym);
+
+  std::vector<std::vector<DefinedImportData *>> V;
+  for (auto &KV : M) {
+    // Sort symbols by name for each group.
+    std::vector<DefinedImportData *> &Syms = KV.second;
+    std::sort(Syms.begin(), Syms.end(),
+              [](DefinedImportData *A, DefinedImportData *B) {
+                return A->getName() < B->getName();
+              });
+    V.push_back(std::move(Syms));
+  }
+  return V;
+}
+
+// Export table
+// See Microsoft PE/COFF spec 4.3 for details.
+
+// A chunk for the delay import descriptor table etnry.
+class DelayDirectoryChunk : public Chunk {
+public:
+  explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
+
+  size_t getSize() const override {
+    return sizeof(delay_import_directory_table_entry);
+  }
+
+  void writeTo(uint8_t *Buf) const override {
+    auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff);
+    E->Attributes = 1;
+    E->Name = DLLName->getRVA();
+    E->ModuleHandle = ModuleHandle->getRVA();
+    E->DelayImportAddressTable = AddressTab->getRVA();
+    E->DelayImportNameTable = NameTab->getRVA();
+  }
+
+  Chunk *DLLName;
+  Chunk *ModuleHandle;
+  Chunk *AddressTab;
+  Chunk *NameTab;
+};
+
+// Initial contents for delay-loaded functions.
+// This code calls __delayLoadHelper2 function to resolve a symbol
+// and then overwrites its jump table slot with the result
+// for subsequent function calls.
+static const uint8_t ThunkX64[] = {
+    0x51,                               // push    rcx
+    0x52,                               // push    rdx
+    0x41, 0x50,                         // push    r8
+    0x41, 0x51,                         // push    r9
+    0x48, 0x83, 0xEC, 0x48,             // sub     rsp, 48h
+    0x66, 0x0F, 0x7F, 0x04, 0x24,       // movdqa  xmmword ptr [rsp], xmm0
+    0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa  xmmword ptr [rsp+10h], xmm1
+    0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa  xmmword ptr [rsp+20h], xmm2
+    0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa  xmmword ptr [rsp+30h], xmm3
+    0x48, 0x8D, 0x15, 0, 0, 0, 0,       // lea     rdx, [__imp_<FUNCNAME>]
+    0x48, 0x8D, 0x0D, 0, 0, 0, 0,       // lea     rcx, [___DELAY_IMPORT_...]
+    0xE8, 0, 0, 0, 0,                   // call    __delayLoadHelper2
+    0x66, 0x0F, 0x6F, 0x04, 0x24,       // movdqa  xmm0, xmmword ptr [rsp]
+    0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa  xmm1, xmmword ptr [rsp+10h]
+    0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa  xmm2, xmmword ptr [rsp+20h]
+    0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa  xmm3, xmmword ptr [rsp+30h]
+    0x48, 0x83, 0xC4, 0x48,             // add     rsp, 48h
+    0x41, 0x59,                         // pop     r9
+    0x41, 0x58,                         // pop     r8
+    0x5A,                               // pop     rdx
+    0x59,                               // pop     rcx
+    0xFF, 0xE0,                         // jmp     rax
+};
+
+static const uint8_t ThunkX86[] = {
+    0x51,              // push  ecx
+    0x52,              // push  edx
+    0x68, 0, 0, 0, 0,  // push  offset ___imp__<FUNCNAME>
+    0x68, 0, 0, 0, 0,  // push  offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
+    0xE8, 0, 0, 0, 0,  // call  ___delayLoadHelper2@8
+    0x5A,              // pop   edx
+    0x59,              // pop   ecx
+    0xFF, 0xE0,        // jmp   eax
+};
+
+// A chunk for the delay import thunk.
+class ThunkChunkX64 : public Chunk {
+public:
+  ThunkChunkX64(Defined *I, Chunk *D, Defined *H)
+      : Imp(I), Desc(D), Helper(H) {}
+
+  size_t getSize() const override { return sizeof(ThunkX64); }
+
+  void writeTo(uint8_t *Buf) const override {
+    memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64));
+    write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40);
+    write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47);
+    write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52);
+  }
+
+  Defined *Imp = nullptr;
+  Chunk *Desc = nullptr;
+  Defined *Helper = nullptr;
+};
+
+class ThunkChunkX86 : public Chunk {
+public:
+  ThunkChunkX86(Defined *I, Chunk *D, Defined *H)
+      : Imp(I), Desc(D), Helper(H) {}
+
+  size_t getSize() const override { return sizeof(ThunkX86); }
+
+  void writeTo(uint8_t *Buf) const override {
+    memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86));
+    write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase);
+    write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase);
+    write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17);
+  }
+
+  void getBaserels(std::vector<Baserel> *Res) override {
+    Res->emplace_back(RVA + 3);
+    Res->emplace_back(RVA + 8);
+  }
+
+  Defined *Imp = nullptr;
+  Chunk *Desc = nullptr;
+  Defined *Helper = nullptr;
+};
+
+// A chunk for the import descriptor table.
+class DelayAddressChunk : public Chunk {
+public:
+  explicit DelayAddressChunk(Chunk *C) : Thunk(C) {}
+  size_t getSize() const override { return ptrSize(); }
+
+  void writeTo(uint8_t *Buf) const override {
+    if (Config->is64()) {
+      write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase);
+    } else {
+      write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase);
+    }
+  }
+
+  void getBaserels(std::vector<Baserel> *Res) override {
+    Res->emplace_back(RVA);
+  }
+
+  Chunk *Thunk;
+};
+
+// Export table
+// Read Microsoft PE/COFF spec 5.3 for details.
+
+// A chunk for the export descriptor table.
+class ExportDirectoryChunk : public Chunk {
+public:
+  ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
+      : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
+        OrdinalTab(O) {}
+
+  size_t getSize() const override {
+    return sizeof(export_directory_table_entry);
+  }
+
+  void writeTo(uint8_t *Buf) const override {
+    auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff);
+    E->NameRVA = DLLName->getRVA();
+    E->OrdinalBase = 0;
+    E->AddressTableEntries = MaxOrdinal + 1;
+    E->NumberOfNamePointers = NameTabSize;
+    E->ExportAddressTableRVA = AddressTab->getRVA();
+    E->NamePointerRVA = NameTab->getRVA();
+    E->OrdinalTableRVA = OrdinalTab->getRVA();
+  }
+
+  uint16_t MaxOrdinal;
+  uint16_t NameTabSize;
+  Chunk *DLLName;
+  Chunk *AddressTab;
+  Chunk *NameTab;
+  Chunk *OrdinalTab;
+};
+
+class AddressTableChunk : public Chunk {
+public:
+  explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
+  size_t getSize() const override { return Size * 4; }
+
+  void writeTo(uint8_t *Buf) const override {
+    for (Export &E : Config->Exports) {
+      uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4;
+      if (E.ForwardChunk) {
+        write32le(P, E.ForwardChunk->getRVA());
+      } else {
+        write32le(P, cast<Defined>(E.Sym)->getRVA());
+      }
+    }
+  }
+
+private:
+  size_t Size;
+};
+
+class NamePointersChunk : public Chunk {
+public:
+  explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
+  size_t getSize() const override { return Chunks.size() * 4; }
+
+  void writeTo(uint8_t *Buf) const override {
+    uint8_t *P = Buf + OutputSectionOff;
+    for (Chunk *C : Chunks) {
+      write32le(P, C->getRVA());
+      P += 4;
+    }
+  }
+
+private:
+  std::vector<Chunk *> Chunks;
+};
+
+class ExportOrdinalChunk : public Chunk {
+public:
+  explicit ExportOrdinalChunk(size_t I) : Size(I) {}
+  size_t getSize() const override { return Size * 2; }
+
+  void writeTo(uint8_t *Buf) const override {
+    uint8_t *P = Buf + OutputSectionOff;
+    for (Export &E : Config->Exports) {
+      if (E.Noname)
+        continue;
+      write16le(P, E.Ordinal);
+      P += 2;
+    }
+  }
+
+private:
+  size_t Size;
+};
+
+} // anonymous namespace
+
+uint64_t IdataContents::getDirSize() {
+  return Dirs.size() * sizeof(ImportDirectoryTableEntry);
+}
+
+uint64_t IdataContents::getIATSize() {
+  return Addresses.size() * ptrSize();
+}
+
+// Returns a list of .idata contents.
+// See Microsoft PE/COFF spec 5.4 for details.
+std::vector<Chunk *> IdataContents::getChunks() {
+  create();
+
+  // The loader assumes a specific order of data.
+  // Add each type in the correct order.
+  std::vector<Chunk *> V;
+  V.insert(V.end(), Dirs.begin(), Dirs.end());
+  V.insert(V.end(), Lookups.begin(), Lookups.end());
+  V.insert(V.end(), Addresses.begin(), Addresses.end());
+  V.insert(V.end(), Hints.begin(), Hints.end());
+  V.insert(V.end(), DLLNames.begin(), DLLNames.end());
+  return V;
+}
+
+void IdataContents::create() {
+  std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+  // Create .idata contents for each DLL.
+  for (std::vector<DefinedImportData *> &Syms : V) {
+    // Create lookup and address tables. If they have external names,
+    // we need to create HintName chunks to store the names.
+    // If they don't (if they are import-by-ordinals), we store only
+    // ordinal values to the table.
+    size_t Base = Lookups.size();
+    for (DefinedImportData *S : Syms) {
+      uint16_t Ord = S->getOrdinal();
+      if (S->getExternalName().empty()) {
+        Lookups.push_back(make<OrdinalOnlyChunk>(Ord));
+        Addresses.push_back(make<OrdinalOnlyChunk>(Ord));
+        continue;
+      }
+      auto *C = make<HintNameChunk>(S->getExternalName(), Ord);
+      Lookups.push_back(make<LookupChunk>(C));
+      Addresses.push_back(make<LookupChunk>(C));
+      Hints.push_back(C);
+    }
+    // Terminate with null values.
+    Lookups.push_back(make<NullChunk>(ptrSize()));
+    Addresses.push_back(make<NullChunk>(ptrSize()));
+
+    for (int I = 0, E = Syms.size(); I < E; ++I)
+      Syms[I]->setLocation(Addresses[Base + I]);
+
+    // Create the import table header.
+    DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+    auto *Dir = make<ImportDirectoryChunk>(DLLNames.back());
+    Dir->LookupTab = Lookups[Base];
+    Dir->AddressTab = Addresses[Base];
+    Dirs.push_back(Dir);
+  }
+  // Add null terminator.
+  Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
+}
+
+std::vector<Chunk *> DelayLoadContents::getChunks() {
+  std::vector<Chunk *> V;
+  V.insert(V.end(), Dirs.begin(), Dirs.end());
+  V.insert(V.end(), Names.begin(), Names.end());
+  V.insert(V.end(), HintNames.begin(), HintNames.end());
+  V.insert(V.end(), DLLNames.begin(), DLLNames.end());
+  return V;
+}
+
+std::vector<Chunk *> DelayLoadContents::getDataChunks() {
+  std::vector<Chunk *> V;
+  V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end());
+  V.insert(V.end(), Addresses.begin(), Addresses.end());
+  return V;
+}
+
+uint64_t DelayLoadContents::getDirSize() {
+  return Dirs.size() * sizeof(delay_import_directory_table_entry);
+}
+
+void DelayLoadContents::create(Defined *H) {
+  Helper = H;
+  std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+  // Create .didat contents for each DLL.
+  for (std::vector<DefinedImportData *> &Syms : V) {
+    // Create the delay import table header.
+    DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+    auto *Dir = make<DelayDirectoryChunk>(DLLNames.back());
+
+    size_t Base = Addresses.size();
+    for (DefinedImportData *S : Syms) {
+      Chunk *T = newThunkChunk(S, Dir);
+      auto *A = make<DelayAddressChunk>(T);
+      Addresses.push_back(A);
+      Thunks.push_back(T);
+      StringRef ExtName = S->getExternalName();
+      if (ExtName.empty()) {
+        Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal()));
+      } else {
+        auto *C = make<HintNameChunk>(ExtName, 0);
+        Names.push_back(make<LookupChunk>(C));
+        HintNames.push_back(C);
+      }
+    }
+    // Terminate with null values.
+    Addresses.push_back(make<NullChunk>(8));
+    Names.push_back(make<NullChunk>(8));
+
+    for (int I = 0, E = Syms.size(); I < E; ++I)
+      Syms[I]->setLocation(Addresses[Base + I]);
+    auto *MH = make<NullChunk>(8);
+    MH->setAlign(8);
+    ModuleHandles.push_back(MH);
+
+    // Fill the delay import table header fields.
+    Dir->ModuleHandle = MH;
+    Dir->AddressTab = Addresses[Base];
+    Dir->NameTab = Names[Base];
+    Dirs.push_back(Dir);
+  }
+  // Add null terminator.
+  Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
+}
+
+Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
+  switch (Config->Machine) {
+  case AMD64:
+    return make<ThunkChunkX64>(S, Dir, Helper);
+  case I386:
+    return make<ThunkChunkX86>(S, Dir, Helper);
+  default:
+    llvm_unreachable("unsupported machine type");
+  }
+}
+
+EdataContents::EdataContents() {
+  uint16_t MaxOrdinal = 0;
+  for (Export &E : Config->Exports)
+    MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
+
+  auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile));
+  auto *AddressTab = make<AddressTableChunk>(MaxOrdinal);
+  std::vector<Chunk *> Names;
+  for (Export &E : Config->Exports)
+    if (!E.Noname)
+      Names.push_back(make<StringChunk>(E.ExportName));
+
+  std::vector<Chunk *> Forwards;
+  for (Export &E : Config->Exports) {
+    if (E.ForwardTo.empty())
+      continue;
+    E.ForwardChunk = make<StringChunk>(E.ForwardTo);
+    Forwards.push_back(E.ForwardChunk);
+  }
+
+  auto *NameTab = make<NamePointersChunk>(Names);
+  auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size());
+  auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName,
+                                         AddressTab, NameTab, OrdinalTab);
+  Chunks.push_back(Dir);
+  Chunks.push_back(DLLName);
+  Chunks.push_back(AddressTab);
+  Chunks.push_back(NameTab);
+  Chunks.push_back(OrdinalTab);
+  Chunks.insert(Chunks.end(), Names.begin(), Names.end());
+  Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end());
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/DLL.h b/COFF/DLL.h
new file mode 100644 (file)
index 0000000..ad31278
--- /dev/null
@@ -0,0 +1,84 @@
+//===- DLL.h ----------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_DLL_H
+#define LLD_COFF_DLL_H
+
+#include "Chunks.h"
+#include "Symbols.h"
+
+namespace lld {
+namespace coff {
+
+// Windows-specific.
+// IdataContents creates all chunks for the DLL import table.
+// You are supposed to call add() to add symbols and then
+// call getChunks() to get a list of chunks.
+class IdataContents {
+public:
+  void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+  bool empty() { return Imports.empty(); }
+  std::vector<Chunk *> getChunks();
+
+  uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+  uint64_t getDirSize();
+  uint64_t getIATRVA() { return Addresses[0]->getRVA(); }
+  uint64_t getIATSize();
+
+private:
+  void create();
+
+  std::vector<DefinedImportData *> Imports;
+  std::vector<Chunk *> Dirs;
+  std::vector<Chunk *> Lookups;
+  std::vector<Chunk *> Addresses;
+  std::vector<Chunk *> Hints;
+  std::vector<Chunk *> DLLNames;
+};
+
+// Windows-specific.
+// DelayLoadContents creates all chunks for the delay-load DLL import table.
+class DelayLoadContents {
+public:
+  void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+  bool empty() { return Imports.empty(); }
+  void create(Defined *Helper);
+  std::vector<Chunk *> getChunks();
+  std::vector<Chunk *> getDataChunks();
+  ArrayRef<Chunk *> getCodeChunks() { return Thunks; }
+
+  uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+  uint64_t getDirSize();
+
+private:
+  Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir);
+
+  Defined *Helper;
+  std::vector<DefinedImportData *> Imports;
+  std::vector<Chunk *> Dirs;
+  std::vector<Chunk *> ModuleHandles;
+  std::vector<Chunk *> Addresses;
+  std::vector<Chunk *> Names;
+  std::vector<Chunk *> HintNames;
+  std::vector<Chunk *> Thunks;
+  std::vector<Chunk *> DLLNames;
+};
+
+// Windows-specific.
+// EdataContents creates all chunks for the DLL export table.
+class EdataContents {
+public:
+  EdataContents();
+  std::vector<Chunk *> Chunks;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
new file mode 100644 (file)
index 0000000..6df59e4
--- /dev/null
@@ -0,0 +1,1181 @@
+//===- Driver.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Memory.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/COFFModuleDefinition.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/TarWriter.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
+#include <algorithm>
+#include <memory>
+
+#include <future>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::COFF;
+using llvm::sys::Process;
+
+namespace lld {
+namespace coff {
+
+Configuration *Config;
+LinkerDriver *Driver;
+
+BumpPtrAllocator BAlloc;
+StringSaver Saver{BAlloc};
+std::vector<SpecificAllocBase *> SpecificAllocBase::Instances;
+
+bool link(ArrayRef<const char *> Args, raw_ostream &Diag) {
+  ErrorCount = 0;
+  ErrorOS = &Diag;
+  Config = make<Configuration>();
+  Config->Argv = {Args.begin(), Args.end()};
+  Config->ColorDiagnostics =
+      (ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
+  Driver = make<LinkerDriver>();
+  Driver->link(Args);
+  return !ErrorCount;
+}
+
+// Drop directory components and replace extension with ".exe" or ".dll".
+static std::string getOutputPath(StringRef Path) {
+  auto P = Path.find_last_of("\\/");
+  StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1);
+  const char* E = Config->DLL ? ".dll" : ".exe";
+  return (S.substr(0, S.rfind('.')) + E).str();
+}
+
+// ErrorOr is not default constructible, so it cannot be used as the type
+// parameter of a future.
+// FIXME: We could open the file in createFutureForFile and avoid needing to
+// return an error here, but for the moment that would cost us a file descriptor
+// (a limited resource on Windows) for the duration that the future is pending.
+typedef std::pair<std::unique_ptr<MemoryBuffer>, std::error_code> MBErrPair;
+
+// Create a std::future that opens and maps a file using the best strategy for
+// the host platform.
+static std::future<MBErrPair> createFutureForFile(std::string Path) {
+#if LLVM_ON_WIN32
+  // On Windows, file I/O is relatively slow so it is best to do this
+  // asynchronously.
+  auto Strategy = std::launch::async;
+#else
+  auto Strategy = std::launch::deferred;
+#endif
+  return std::async(Strategy, [=]() {
+    auto MBOrErr = MemoryBuffer::getFile(Path);
+    if (!MBOrErr)
+      return MBErrPair{nullptr, MBOrErr.getError()};
+    return MBErrPair{std::move(*MBOrErr), std::error_code()};
+  });
+}
+
+MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
+  MemoryBufferRef MBRef = *MB;
+  make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
+
+  if (Driver->Tar)
+    Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()),
+                        MBRef.getBuffer());
+  return MBRef;
+}
+
+void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB) {
+  MemoryBufferRef MBRef = takeBuffer(std::move(MB));
+
+  // File type is detected by contents, not by file extension.
+  file_magic Magic = identify_magic(MBRef.getBuffer());
+  if (Magic == file_magic::windows_resource) {
+    Resources.push_back(MBRef);
+    return;
+  }
+
+  FilePaths.push_back(MBRef.getBufferIdentifier());
+  if (Magic == file_magic::archive)
+    return Symtab.addFile(make<ArchiveFile>(MBRef));
+  if (Magic == file_magic::bitcode)
+    return Symtab.addFile(make<BitcodeFile>(MBRef));
+
+  if (Magic == file_magic::coff_cl_gl_object)
+    error(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
+          "Recompile without /GL");
+  else
+    Symtab.addFile(make<ObjectFile>(MBRef));
+}
+
+void LinkerDriver::enqueuePath(StringRef Path) {
+  auto Future =
+      std::make_shared<std::future<MBErrPair>>(createFutureForFile(Path));
+  std::string PathStr = Path;
+  enqueueTask([=]() {
+    auto MBOrErr = Future->get();
+    if (MBOrErr.second)
+      error("could not open " + PathStr + ": " + MBOrErr.second.message());
+    else
+      Driver->addBuffer(std::move(MBOrErr.first));
+  });
+}
+
+void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
+                                    StringRef ParentName) {
+  file_magic Magic = identify_magic(MB.getBuffer());
+  if (Magic == file_magic::coff_import_library) {
+    Symtab.addFile(make<ImportFile>(MB));
+    return;
+  }
+
+  InputFile *Obj;
+  if (Magic == file_magic::coff_object) {
+    Obj = make<ObjectFile>(MB);
+  } else if (Magic == file_magic::bitcode) {
+    Obj = make<BitcodeFile>(MB);
+  } else {
+    error("unknown file type: " + MB.getBufferIdentifier());
+    return;
+  }
+
+  Obj->ParentName = ParentName;
+  Symtab.addFile(Obj);
+  log("Loaded " + toString(Obj) + " for " + SymName);
+}
+
+void LinkerDriver::enqueueArchiveMember(const Archive::Child &C,
+                                        StringRef SymName,
+                                        StringRef ParentName) {
+  if (!C.getParent()->isThin()) {
+    MemoryBufferRef MB = check(
+        C.getMemoryBufferRef(),
+        "could not get the buffer for the member defining symbol " + SymName);
+    enqueueTask([=]() { Driver->addArchiveBuffer(MB, SymName, ParentName); });
+    return;
+  }
+
+  auto Future = std::make_shared<std::future<MBErrPair>>(createFutureForFile(
+      check(C.getFullName(),
+            "could not get the filename for the member defining symbol " +
+                SymName)));
+  enqueueTask([=]() {
+    auto MBOrErr = Future->get();
+    if (MBOrErr.second)
+      fatal(MBOrErr.second,
+            "could not get the buffer for the member defining " + SymName);
+    Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName,
+                             ParentName);
+  });
+}
+
+static bool isDecorated(StringRef Sym) {
+  return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
+}
+
+// Parses .drectve section contents and returns a list of files
+// specified by /defaultlib.
+void LinkerDriver::parseDirectives(StringRef S) {
+  opt::InputArgList Args = Parser.parse(S);
+
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_alternatename:
+      parseAlternateName(Arg->getValue());
+      break;
+    case OPT_defaultlib:
+      if (Optional<StringRef> Path = findLib(Arg->getValue()))
+        enqueuePath(*Path);
+      break;
+    case OPT_export: {
+      Export E = parseExport(Arg->getValue());
+      E.Directives = true;
+      Config->Exports.push_back(E);
+      break;
+    }
+    case OPT_failifmismatch:
+      checkFailIfMismatch(Arg->getValue());
+      break;
+    case OPT_incl:
+      addUndefined(Arg->getValue());
+      break;
+    case OPT_merge:
+      parseMerge(Arg->getValue());
+      break;
+    case OPT_nodefaultlib:
+      Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+      break;
+    case OPT_section:
+      parseSection(Arg->getValue());
+      break;
+    case OPT_editandcontinue:
+    case OPT_fastfail:
+    case OPT_guardsym:
+    case OPT_throwingnew:
+      break;
+    default:
+      error(Arg->getSpelling() + " is not allowed in .drectve");
+    }
+  }
+}
+
+// Find file from search paths. You can omit ".obj", this function takes
+// care of that. Note that the returned path is not guaranteed to exist.
+StringRef LinkerDriver::doFindFile(StringRef Filename) {
+  bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
+  if (HasPathSep)
+    return Filename;
+  bool HasExt = (Filename.find('.') != StringRef::npos);
+  for (StringRef Dir : SearchPaths) {
+    SmallString<128> Path = Dir;
+    sys::path::append(Path, Filename);
+    if (sys::fs::exists(Path.str()))
+      return Saver.save(Path.str());
+    if (!HasExt) {
+      Path.append(".obj");
+      if (sys::fs::exists(Path.str()))
+        return Saver.save(Path.str());
+    }
+  }
+  return Filename;
+}
+
+// Resolves a file path. This never returns the same path
+// (in that case, it returns None).
+Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
+  StringRef Path = doFindFile(Filename);
+  bool Seen = !VisitedFiles.insert(Path.lower()).second;
+  if (Seen)
+    return None;
+  return Path;
+}
+
+// Find library file from search path.
+StringRef LinkerDriver::doFindLib(StringRef Filename) {
+  // Add ".lib" to Filename if that has no file extension.
+  bool HasExt = (Filename.find('.') != StringRef::npos);
+  if (!HasExt)
+    Filename = Saver.save(Filename + ".lib");
+  return doFindFile(Filename);
+}
+
+// Resolves a library path. /nodefaultlib options are taken into
+// consideration. This never returns the same path (in that case,
+// it returns None).
+Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
+  if (Config->NoDefaultLibAll)
+    return None;
+  if (!VisitedLibs.insert(Filename.lower()).second)
+    return None;
+  StringRef Path = doFindLib(Filename);
+  if (Config->NoDefaultLibs.count(Path))
+    return None;
+  if (!VisitedFiles.insert(Path.lower()).second)
+    return None;
+  return Path;
+}
+
+// Parses LIB environment which contains a list of search paths.
+void LinkerDriver::addLibSearchPaths() {
+  Optional<std::string> EnvOpt = Process::GetEnv("LIB");
+  if (!EnvOpt.hasValue())
+    return;
+  StringRef Env = Saver.save(*EnvOpt);
+  while (!Env.empty()) {
+    StringRef Path;
+    std::tie(Path, Env) = Env.split(';');
+    SearchPaths.push_back(Path);
+  }
+}
+
+SymbolBody *LinkerDriver::addUndefined(StringRef Name) {
+  SymbolBody *B = Symtab.addUndefined(Name);
+  Config->GCRoot.insert(B);
+  return B;
+}
+
+// Symbol names are mangled by appending "_" prefix on x86.
+StringRef LinkerDriver::mangle(StringRef Sym) {
+  assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
+  if (Config->Machine == I386)
+    return Saver.save("_" + Sym);
+  return Sym;
+}
+
+// Windows specific -- find default entry point name.
+StringRef LinkerDriver::findDefaultEntry() {
+  // User-defined main functions and their corresponding entry points.
+  static const char *Entries[][2] = {
+      {"main", "mainCRTStartup"},
+      {"wmain", "wmainCRTStartup"},
+      {"WinMain", "WinMainCRTStartup"},
+      {"wWinMain", "wWinMainCRTStartup"},
+  };
+  for (auto E : Entries) {
+    StringRef Entry = Symtab.findMangle(mangle(E[0]));
+    if (!Entry.empty() && !isa<Undefined>(Symtab.find(Entry)->body()))
+      return mangle(E[1]);
+  }
+  return "";
+}
+
+WindowsSubsystem LinkerDriver::inferSubsystem() {
+  if (Config->DLL)
+    return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+  if (Symtab.findUnderscore("main") || Symtab.findUnderscore("wmain"))
+    return IMAGE_SUBSYSTEM_WINDOWS_CUI;
+  if (Symtab.findUnderscore("WinMain") || Symtab.findUnderscore("wWinMain"))
+    return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+  return IMAGE_SUBSYSTEM_UNKNOWN;
+}
+
+static uint64_t getDefaultImageBase() {
+  if (Config->is64())
+    return Config->DLL ? 0x180000000 : 0x140000000;
+  return Config->DLL ? 0x10000000 : 0x400000;
+}
+
+static std::string createResponseFile(const opt::InputArgList &Args,
+                                      ArrayRef<StringRef> FilePaths,
+                                      ArrayRef<StringRef> SearchPaths) {
+  SmallString<0> Data;
+  raw_svector_ostream OS(Data);
+
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_linkrepro:
+    case OPT_INPUT:
+    case OPT_defaultlib:
+    case OPT_libpath:
+      break;
+    default:
+      OS << toString(Arg) << "\n";
+    }
+  }
+
+  for (StringRef Path : SearchPaths) {
+    std::string RelPath = relativeToRoot(Path);
+    OS << "/libpath:" << quote(RelPath) << "\n";
+  }
+
+  for (StringRef Path : FilePaths)
+    OS << quote(relativeToRoot(Path)) << "\n";
+
+  return Data.str();
+}
+
+static unsigned getDefaultDebugType(const opt::InputArgList &Args) {
+  unsigned DebugTypes = static_cast<unsigned>(DebugType::CV);
+  if (Args.hasArg(OPT_driver))
+    DebugTypes |= static_cast<unsigned>(DebugType::PData);
+  if (Args.hasArg(OPT_profile))
+    DebugTypes |= static_cast<unsigned>(DebugType::Fixup);
+  return DebugTypes;
+}
+
+static unsigned parseDebugType(StringRef Arg) {
+  SmallVector<StringRef, 3> Types;
+  Arg.split(Types, ',', /*KeepEmpty=*/false);
+
+  unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+  for (StringRef Type : Types)
+    DebugTypes |= StringSwitch<unsigned>(Type.lower())
+                      .Case("cv", static_cast<unsigned>(DebugType::CV))
+                      .Case("pdata", static_cast<unsigned>(DebugType::PData))
+                      .Case("fixup", static_cast<unsigned>(DebugType::Fixup))
+                      .Default(0);
+  return DebugTypes;
+}
+
+static std::string getMapFile(const opt::InputArgList &Args) {
+  auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file);
+  if (!Arg)
+    return "";
+  if (Arg->getOption().getID() == OPT_lldmap_file)
+    return Arg->getValue();
+
+  assert(Arg->getOption().getID() == OPT_lldmap);
+  StringRef OutFile = Config->OutputFile;
+  return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
+}
+
+static std::string getImplibPath() {
+  if (!Config->Implib.empty())
+    return Config->Implib;
+  SmallString<128> Out = StringRef(Config->OutputFile);
+  sys::path::replace_extension(Out, ".lib");
+  return Out.str();
+}
+
+//
+// The import name is caculated as the following:
+//
+//        | LIBRARY w/ ext |   LIBRARY w/o ext   | no LIBRARY
+//   -----+----------------+---------------------+------------------
+//   LINK | {value}        | {value}.{.dll/.exe} | {output name}
+//    LIB | {value}        | {value}.dll         | {output name}.dll
+//
+static std::string getImportName(bool AsLib) {
+  SmallString<128> Out;
+
+  if (Config->ImportName.empty()) {
+    Out.assign(sys::path::filename(Config->OutputFile));
+    if (AsLib)
+      sys::path::replace_extension(Out, ".dll");
+  } else {
+    Out.assign(Config->ImportName);
+    if (!sys::path::has_extension(Out))
+      sys::path::replace_extension(Out,
+                                   (Config->DLL || AsLib) ? ".dll" : ".exe");
+  }
+
+  return Out.str();
+}
+
+static void createImportLibrary(bool AsLib) {
+  std::vector<COFFShortExport> Exports;
+  for (Export &E1 : Config->Exports) {
+    COFFShortExport E2;
+    // Use SymbolName, which will have any stdcall or fastcall qualifiers.
+    E2.Name = E1.SymbolName;
+    E2.ExtName = E1.ExtName;
+    E2.Ordinal = E1.Ordinal;
+    E2.Noname = E1.Noname;
+    E2.Data = E1.Data;
+    E2.Private = E1.Private;
+    E2.Constant = E1.Constant;
+    Exports.push_back(E2);
+  }
+
+  writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports,
+                     Config->Machine);
+}
+
+static void parseModuleDefs(StringRef Path) {
+  std::unique_ptr<MemoryBuffer> MB = check(
+    MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+  COFFModuleDefinition M =
+      check(parseCOFFModuleDefinition(MB->getMemBufferRef(), Config->Machine));
+
+  if (Config->OutputFile.empty())
+    Config->OutputFile = Saver.save(M.OutputFile);
+  Config->ImportName = Saver.save(M.ImportName);
+  if (M.ImageBase)
+    Config->ImageBase = M.ImageBase;
+  if (M.StackReserve)
+    Config->StackReserve = M.StackReserve;
+  if (M.StackCommit)
+    Config->StackCommit = M.StackCommit;
+  if (M.HeapReserve)
+    Config->HeapReserve = M.HeapReserve;
+  if (M.HeapCommit)
+    Config->HeapCommit = M.HeapCommit;
+  if (M.MajorImageVersion)
+    Config->MajorImageVersion = M.MajorImageVersion;
+  if (M.MinorImageVersion)
+    Config->MinorImageVersion = M.MinorImageVersion;
+  if (M.MajorOSVersion)
+    Config->MajorOSVersion = M.MajorOSVersion;
+  if (M.MinorOSVersion)
+    Config->MinorOSVersion = M.MinorOSVersion;
+
+  for (COFFShortExport E1 : M.Exports) {
+    Export E2;
+    E2.Name = Saver.save(E1.Name);
+    if (E1.isWeak())
+      E2.ExtName = Saver.save(E1.ExtName);
+    E2.Ordinal = E1.Ordinal;
+    E2.Noname = E1.Noname;
+    E2.Data = E1.Data;
+    E2.Private = E1.Private;
+    E2.Constant = E1.Constant;
+    Config->Exports.push_back(E2);
+  }
+}
+
+std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
+  std::vector<MemoryBufferRef> V;
+  Error Err = Error::success();
+  for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+    Archive::Child C =
+        check(COrErr,
+              File->getFileName() + ": could not get the child of the archive");
+    MemoryBufferRef MBRef =
+        check(C.getMemoryBufferRef(),
+              File->getFileName() +
+                  ": could not get the buffer for a child of the archive");
+    V.push_back(MBRef);
+  }
+  if (Err)
+    fatal(File->getFileName() +
+          ": Archive::children failed: " + toString(std::move(Err)));
+  return V;
+}
+
+// A helper function for filterBitcodeFiles.
+static bool needsRebuilding(MemoryBufferRef MB) {
+  // The MSVC linker doesn't support thin archives, so if it's a thin
+  // archive, we always need to rebuild it.
+  std::unique_ptr<Archive> File =
+      check(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier());
+  if (File->isThin())
+    return true;
+
+  // Returns true if the archive contains at least one bitcode file.
+  for (MemoryBufferRef Member : getArchiveMembers(File.get()))
+    if (identify_magic(Member.getBuffer()) == file_magic::bitcode)
+      return true;
+  return false;
+}
+
+// Opens a given path as an archive file and removes bitcode files
+// from them if exists. This function is to appease the MSVC linker as
+// their linker doesn't like archive files containing non-native
+// object files.
+//
+// If a given archive doesn't contain bitcode files, the archive path
+// is returned as-is. Otherwise, a new temporary file is created and
+// its path is returned.
+static Optional<std::string>
+filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) {
+  std::unique_ptr<MemoryBuffer> MB = check(
+      MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+  MemoryBufferRef MBRef = MB->getMemBufferRef();
+  file_magic Magic = identify_magic(MBRef.getBuffer());
+
+  if (Magic == file_magic::bitcode)
+    return None;
+  if (Magic != file_magic::archive)
+    return Path.str();
+  if (!needsRebuilding(MBRef))
+    return Path.str();
+
+  std::unique_ptr<Archive> File =
+      check(Archive::create(MBRef),
+            MBRef.getBufferIdentifier() + ": failed to parse archive");
+
+  std::vector<NewArchiveMember> New;
+  for (MemoryBufferRef Member : getArchiveMembers(File.get()))
+    if (identify_magic(Member.getBuffer()) != file_magic::bitcode)
+      New.emplace_back(Member);
+
+  if (New.empty())
+    return None;
+
+  log("Creating a temporary archive for " + Path + " to remove bitcode files");
+
+  SmallString<128> S;
+  if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path),
+                                             ".lib", S))
+    fatal(EC, "cannot create a temporary file");
+  std::string Temp = S.str();
+  TemporaryFiles.push_back(Temp);
+
+  std::pair<StringRef, std::error_code> Ret =
+      llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU,
+                         /*Deterministics=*/true,
+                         /*Thin=*/false);
+  if (Ret.second)
+    error("failed to create a new archive " + S.str() + ": " + Ret.first);
+  return Temp;
+}
+
+// Create response file contents and invoke the MSVC linker.
+void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
+  std::string Rsp = "/nologo\n";
+  std::vector<std::string> Temps;
+
+  // Write out archive members that we used in symbol resolution and pass these
+  // to MSVC before any archives, so that MSVC uses the same objects to satisfy
+  // references.
+  for (const auto *O : Symtab.ObjectFiles) {
+    if (O->ParentName.empty())
+      continue;
+    SmallString<128> S;
+    int Fd;
+    if (auto EC = sys::fs::createTemporaryFile(
+            "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S))
+      fatal(EC, "cannot create a temporary file");
+    raw_fd_ostream OS(Fd, /*shouldClose*/ true);
+    OS << O->MB.getBuffer();
+    Temps.push_back(S.str());
+    Rsp += quote(S) + "\n";
+  }
+
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_linkrepro:
+    case OPT_lldmap:
+    case OPT_lldmap_file:
+    case OPT_lldsavetemps:
+    case OPT_msvclto:
+      // LLD-specific options are stripped.
+      break;
+    case OPT_opt:
+      if (!StringRef(Arg->getValue()).startswith("lld"))
+        Rsp += toString(Arg) + " ";
+      break;
+    case OPT_INPUT: {
+      if (Optional<StringRef> Path = doFindFile(Arg->getValue())) {
+        if (Optional<std::string> S = filterBitcodeFiles(*Path, Temps))
+          Rsp += quote(*S) + "\n";
+        continue;
+      }
+      Rsp += quote(Arg->getValue()) + "\n";
+      break;
+    }
+    default:
+      Rsp += toString(Arg) + "\n";
+    }
+  }
+
+  std::vector<StringRef> ObjectFiles = Symtab.compileBitcodeFiles();
+  runMSVCLinker(Rsp, ObjectFiles);
+
+  for (StringRef Path : Temps)
+    sys::fs::remove(Path);
+}
+
+void LinkerDriver::enqueueTask(std::function<void()> Task) {
+  TaskQueue.push_back(std::move(Task));
+}
+
+bool LinkerDriver::run() {
+  bool DidWork = !TaskQueue.empty();
+  while (!TaskQueue.empty()) {
+    TaskQueue.front()();
+    TaskQueue.pop_front();
+  }
+  return DidWork;
+}
+
+void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
+  // If the first command line argument is "/lib", link.exe acts like lib.exe.
+  // We call our own implementation of lib.exe that understands bitcode files.
+  if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) {
+    if (llvm::libDriverMain(ArgsArr.slice(1)) != 0)
+      fatal("lib failed");
+    return;
+  }
+
+  // Needed for LTO.
+  InitializeAllTargetInfos();
+  InitializeAllTargets();
+  InitializeAllTargetMCs();
+  InitializeAllAsmParsers();
+  InitializeAllAsmPrinters();
+  InitializeAllDisassemblers();
+
+  // Parse command line options.
+  opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
+
+  // Parse and evaluate -mllvm options.
+  std::vector<const char *> V;
+  V.push_back("lld-link (LLVM option parsing)");
+  for (auto *Arg : Args.filtered(OPT_mllvm))
+    V.push_back(Arg->getValue());
+  cl::ParseCommandLineOptions(V.size(), V.data());
+
+  // Handle /errorlimit early, because error() depends on it.
+  if (auto *Arg = Args.getLastArg(OPT_errorlimit)) {
+    int N = 20;
+    StringRef S = Arg->getValue();
+    if (S.getAsInteger(10, N))
+      error(Arg->getSpelling() + " number expected, but got " + S);
+    Config->ErrorLimit = N;
+  }
+
+  // Handle /help
+  if (Args.hasArg(OPT_help)) {
+    printHelp(ArgsArr[0]);
+    return;
+  }
+
+  if (auto *Arg = Args.getLastArg(OPT_linkrepro)) {
+    SmallString<64> Path = StringRef(Arg->getValue());
+    sys::path::append(Path, "repro.tar");
+
+    Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
+        TarWriter::create(Path, "repro");
+
+    if (ErrOrWriter) {
+      Tar = std::move(*ErrOrWriter);
+    } else {
+      error("/linkrepro: failed to open " + Path + ": " +
+            toString(ErrOrWriter.takeError()));
+    }
+  }
+
+  if (!Args.hasArgNoClaim(OPT_INPUT)) {
+    if (Args.hasArgNoClaim(OPT_deffile))
+      Config->NoEntry = true;
+    else
+      fatal("no input files");
+  }
+
+  // Construct search path list.
+  SearchPaths.push_back("");
+  for (auto *Arg : Args.filtered(OPT_libpath))
+    SearchPaths.push_back(Arg->getValue());
+  addLibSearchPaths();
+
+  // Handle /out
+  if (auto *Arg = Args.getLastArg(OPT_out))
+    Config->OutputFile = Arg->getValue();
+
+  // Handle /verbose
+  if (Args.hasArg(OPT_verbose))
+    Config->Verbose = true;
+
+  // Handle /force or /force:unresolved
+  if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved))
+    Config->Force = true;
+
+  // Handle /debug
+  if (Args.hasArg(OPT_debug)) {
+    Config->Debug = true;
+    Config->DebugTypes =
+        Args.hasArg(OPT_debugtype)
+            ? parseDebugType(Args.getLastArg(OPT_debugtype)->getValue())
+            : getDefaultDebugType(Args);
+  }
+
+  // Create a dummy PDB file to satisfy build sytem rules.
+  if (auto *Arg = Args.getLastArg(OPT_pdb))
+    Config->PDBPath = Arg->getValue();
+
+  // Handle /noentry
+  if (Args.hasArg(OPT_noentry)) {
+    if (Args.hasArg(OPT_dll))
+      Config->NoEntry = true;
+    else
+      error("/noentry must be specified with /dll");
+  }
+
+  // Handle /dll
+  if (Args.hasArg(OPT_dll)) {
+    Config->DLL = true;
+    Config->ManifestID = 2;
+  }
+
+  // Handle /fixed
+  if (Args.hasArg(OPT_fixed)) {
+    if (Args.hasArg(OPT_dynamicbase)) {
+      error("/fixed must not be specified with /dynamicbase");
+    } else {
+      Config->Relocatable = false;
+      Config->DynamicBase = false;
+    }
+  }
+
+  if (Args.hasArg(OPT_appcontainer))
+    Config->AppContainer = true;
+
+  // Handle /machine
+  if (auto *Arg = Args.getLastArg(OPT_machine))
+    Config->Machine = getMachineType(Arg->getValue());
+
+  // Handle /nodefaultlib:<filename>
+  for (auto *Arg : Args.filtered(OPT_nodefaultlib))
+    Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+
+  // Handle /nodefaultlib
+  if (Args.hasArg(OPT_nodefaultlib_all))
+    Config->NoDefaultLibAll = true;
+
+  // Handle /base
+  if (auto *Arg = Args.getLastArg(OPT_base))
+    parseNumbers(Arg->getValue(), &Config->ImageBase);
+
+  // Handle /stack
+  if (auto *Arg = Args.getLastArg(OPT_stack))
+    parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+
+  // Handle /heap
+  if (auto *Arg = Args.getLastArg(OPT_heap))
+    parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
+
+  // Handle /version
+  if (auto *Arg = Args.getLastArg(OPT_version))
+    parseVersion(Arg->getValue(), &Config->MajorImageVersion,
+                 &Config->MinorImageVersion);
+
+  // Handle /subsystem
+  if (auto *Arg = Args.getLastArg(OPT_subsystem))
+    parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
+                   &Config->MinorOSVersion);
+
+  // Handle /alternatename
+  for (auto *Arg : Args.filtered(OPT_alternatename))
+    parseAlternateName(Arg->getValue());
+
+  // Handle /include
+  for (auto *Arg : Args.filtered(OPT_incl))
+    addUndefined(Arg->getValue());
+
+  // Handle /implib
+  if (auto *Arg = Args.getLastArg(OPT_implib))
+    Config->Implib = Arg->getValue();
+
+  // Handle /opt
+  for (auto *Arg : Args.filtered(OPT_opt)) {
+    std::string Str = StringRef(Arg->getValue()).lower();
+    SmallVector<StringRef, 1> Vec;
+    StringRef(Str).split(Vec, ',');
+    for (StringRef S : Vec) {
+      if (S == "noref") {
+        Config->DoGC = false;
+        Config->DoICF = false;
+        continue;
+      }
+      if (S == "icf" || StringRef(S).startswith("icf=")) {
+        Config->DoICF = true;
+        continue;
+      }
+      if (S == "noicf") {
+        Config->DoICF = false;
+        continue;
+      }
+      if (StringRef(S).startswith("lldlto=")) {
+        StringRef OptLevel = StringRef(S).substr(7);
+        if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
+            Config->LTOOptLevel > 3)
+          error("/opt:lldlto: invalid optimization level: " + OptLevel);
+        continue;
+      }
+      if (StringRef(S).startswith("lldltojobs=")) {
+        StringRef Jobs = StringRef(S).substr(11);
+        if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
+          error("/opt:lldltojobs: invalid job count: " + Jobs);
+        continue;
+      }
+      if (StringRef(S).startswith("lldltopartitions=")) {
+        StringRef N = StringRef(S).substr(17);
+        if (N.getAsInteger(10, Config->LTOPartitions) ||
+            Config->LTOPartitions == 0)
+          error("/opt:lldltopartitions: invalid partition count: " + N);
+        continue;
+      }
+      if (S != "ref" && S != "lbr" && S != "nolbr")
+        error("/opt: unknown option: " + S);
+    }
+  }
+
+  // Handle /lldsavetemps
+  if (Args.hasArg(OPT_lldsavetemps))
+    Config->SaveTemps = true;
+
+  // Handle /failifmismatch
+  for (auto *Arg : Args.filtered(OPT_failifmismatch))
+    checkFailIfMismatch(Arg->getValue());
+
+  // Handle /merge
+  for (auto *Arg : Args.filtered(OPT_merge))
+    parseMerge(Arg->getValue());
+
+  // Handle /section
+  for (auto *Arg : Args.filtered(OPT_section))
+    parseSection(Arg->getValue());
+
+  // Handle /manifestdependency. This enables /manifest unless /manifest:no is
+  // also passed.
+  if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) {
+    Config->ManifestDependency = Arg->getValue();
+    Config->Manifest = Configuration::SideBySide;
+  }
+
+  // Handle /manifest and /manifest:
+  if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
+    if (Arg->getOption().getID() == OPT_manifest)
+      Config->Manifest = Configuration::SideBySide;
+    else
+      parseManifest(Arg->getValue());
+  }
+
+  // Handle /manifestuac
+  if (auto *Arg = Args.getLastArg(OPT_manifestuac))
+    parseManifestUAC(Arg->getValue());
+
+  // Handle /manifestfile
+  if (auto *Arg = Args.getLastArg(OPT_manifestfile))
+    Config->ManifestFile = Arg->getValue();
+
+  // Handle /manifestinput
+  for (auto *Arg : Args.filtered(OPT_manifestinput))
+    Config->ManifestInput.push_back(Arg->getValue());
+
+  if (!Config->ManifestInput.empty() &&
+      Config->Manifest != Configuration::Embed) {
+    fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED");
+  }
+
+  // Handle miscellaneous boolean flags.
+  if (Args.hasArg(OPT_allowisolation_no))
+    Config->AllowIsolation = false;
+  if (Args.hasArg(OPT_dynamicbase_no))
+    Config->DynamicBase = false;
+  if (Args.hasArg(OPT_nxcompat_no))
+    Config->NxCompat = false;
+  if (Args.hasArg(OPT_tsaware_no))
+    Config->TerminalServerAware = false;
+  if (Args.hasArg(OPT_nosymtab))
+    Config->WriteSymtab = false;
+
+  Config->MapFile = getMapFile(Args);
+
+  if (ErrorCount)
+    return;
+
+  // Create a list of input files. Files can be given as arguments
+  // for /defaultlib option.
+  std::vector<MemoryBufferRef> MBs;
+  for (auto *Arg : Args.filtered(OPT_INPUT))
+    if (Optional<StringRef> Path = findFile(Arg->getValue()))
+      enqueuePath(*Path);
+  for (auto *Arg : Args.filtered(OPT_defaultlib))
+    if (Optional<StringRef> Path = findLib(Arg->getValue()))
+      enqueuePath(*Path);
+
+  // Windows specific -- Create a resource file containing a manifest file.
+  if (Config->Manifest == Configuration::Embed)
+    addBuffer(createManifestRes());
+
+  // Read all input files given via the command line.
+  run();
+
+  // We should have inferred a machine type by now from the input files, but if
+  // not we assume x64.
+  if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+    warn("/machine is not specified. x64 is assumed");
+    Config->Machine = AMD64;
+  }
+
+  // Input files can be Windows resource files (.res files). We use
+  // WindowsResource to convert resource files to a regular COFF file,
+  // then link the resulting file normally.
+  if (!Resources.empty())
+    addBuffer(convertResToCOFF(Resources));
+
+  if (Tar)
+    Tar->append("response.txt",
+                createResponseFile(Args, FilePaths,
+                                   ArrayRef<StringRef>(SearchPaths).slice(1)));
+
+  // Handle /largeaddressaware
+  if (Config->is64() || Args.hasArg(OPT_largeaddressaware))
+    Config->LargeAddressAware = true;
+
+  // Handle /highentropyva
+  if (Config->is64() && !Args.hasArg(OPT_highentropyva_no))
+    Config->HighEntropyVA = true;
+
+  // Handle /entry and /dll
+  if (auto *Arg = Args.getLastArg(OPT_entry)) {
+    Config->Entry = addUndefined(mangle(Arg->getValue()));
+  } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) {
+    StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
+                                            : "_DllMainCRTStartup";
+    Config->Entry = addUndefined(S);
+  } else if (!Config->NoEntry) {
+    // Windows specific -- If entry point name is not given, we need to
+    // infer that from user-defined entry name.
+    StringRef S = findDefaultEntry();
+    if (S.empty())
+      fatal("entry point must be defined");
+    Config->Entry = addUndefined(S);
+    log("Entry name inferred: " + S);
+  }
+
+  // Handle /export
+  for (auto *Arg : Args.filtered(OPT_export)) {
+    Export E = parseExport(Arg->getValue());
+    if (Config->Machine == I386) {
+      if (!isDecorated(E.Name))
+        E.Name = Saver.save("_" + E.Name);
+      if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+        E.ExtName = Saver.save("_" + E.ExtName);
+    }
+    Config->Exports.push_back(E);
+  }
+
+  // Handle /def
+  if (auto *Arg = Args.getLastArg(OPT_deffile)) {
+    // parseModuleDefs mutates Config object.
+    parseModuleDefs(Arg->getValue());
+  }
+
+  // Handle generation of import library from a def file.
+  if (!Args.hasArgNoClaim(OPT_INPUT)) {
+    fixupExports();
+    createImportLibrary(/*AsLib=*/true);
+    exit(0);
+  }
+
+  // Handle /delayload
+  for (auto *Arg : Args.filtered(OPT_delayload)) {
+    Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
+    if (Config->Machine == I386) {
+      Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8");
+    } else {
+      Config->DelayLoadHelper = addUndefined("__delayLoadHelper2");
+    }
+  }
+
+  // Set default image name if neither /out or /def set it.
+  if (Config->OutputFile.empty()) {
+    Config->OutputFile =
+        getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
+  }
+
+  // Put the PDB next to the image if no /pdb flag was passed.
+  if (Config->Debug && Config->PDBPath.empty()) {
+    Config->PDBPath = Config->OutputFile;
+    sys::path::replace_extension(Config->PDBPath, ".pdb");
+  }
+
+  // Disable PDB generation if the user requested it.
+  if (Args.hasArg(OPT_nopdb))
+    Config->PDBPath = "";
+
+  // Set default image base if /base is not given.
+  if (Config->ImageBase == uint64_t(-1))
+    Config->ImageBase = getDefaultImageBase();
+
+  Symtab.addSynthetic(mangle("__ImageBase"), nullptr);
+  if (Config->Machine == I386) {
+    Symtab.addAbsolute("___safe_se_handler_table", 0);
+    Symtab.addAbsolute("___safe_se_handler_count", 0);
+  }
+
+  // We do not support /guard:cf (control flow protection) yet.
+  // Define CFG symbols anyway so that we can link MSVC 2015 CRT.
+  Symtab.addAbsolute(mangle("__guard_fids_count"), 0);
+  Symtab.addAbsolute(mangle("__guard_fids_table"), 0);
+  Symtab.addAbsolute(mangle("__guard_flags"), 0x100);
+  Symtab.addAbsolute(mangle("__guard_iat_count"), 0);
+  Symtab.addAbsolute(mangle("__guard_iat_table"), 0);
+  Symtab.addAbsolute(mangle("__guard_longjmp_count"), 0);
+  Symtab.addAbsolute(mangle("__guard_longjmp_table"), 0);
+
+  // This code may add new undefined symbols to the link, which may enqueue more
+  // symbol resolution tasks, so we need to continue executing tasks until we
+  // converge.
+  do {
+    // Windows specific -- if entry point is not found,
+    // search for its mangled names.
+    if (Config->Entry)
+      Symtab.mangleMaybe(Config->Entry);
+
+    // Windows specific -- Make sure we resolve all dllexported symbols.
+    for (Export &E : Config->Exports) {
+      if (!E.ForwardTo.empty())
+        continue;
+      E.Sym = addUndefined(E.Name);
+      if (!E.Directives)
+        Symtab.mangleMaybe(E.Sym);
+    }
+
+    // Add weak aliases. Weak aliases is a mechanism to give remaining
+    // undefined symbols final chance to be resolved successfully.
+    for (auto Pair : Config->AlternateNames) {
+      StringRef From = Pair.first;
+      StringRef To = Pair.second;
+      Symbol *Sym = Symtab.find(From);
+      if (!Sym)
+        continue;
+      if (auto *U = dyn_cast<Undefined>(Sym->body()))
+        if (!U->WeakAlias)
+          U->WeakAlias = Symtab.addUndefined(To);
+    }
+
+    // Windows specific -- if __load_config_used can be resolved, resolve it.
+    if (Symtab.findUnderscore("_load_config_used"))
+      addUndefined(mangle("_load_config_used"));
+  } while (run());
+
+  if (ErrorCount)
+    return;
+
+  // If /msvclto is given, we use the MSVC linker to link LTO output files.
+  // This is useful because MSVC link.exe can generate complete PDBs.
+  if (Args.hasArg(OPT_msvclto)) {
+    invokeMSVC(Args);
+    exit(0);
+  }
+
+  // Do LTO by compiling bitcode input files to a set of native COFF files then
+  // link those files.
+  Symtab.addCombinedLTOObjects();
+  run();
+
+  // Make sure we have resolved all symbols.
+  Symtab.reportRemainingUndefines();
+
+  // Windows specific -- if no /subsystem is given, we need to infer
+  // that from entry point name.
+  if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
+    Config->Subsystem = inferSubsystem();
+    if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+      fatal("subsystem must be defined");
+  }
+
+  // Handle /safeseh.
+  if (Args.hasArg(OPT_safeseh)) {
+    for (ObjectFile *File : Symtab.ObjectFiles)
+      if (!File->SEHCompat)
+        error("/safeseh: " + File->getName() + " is not compatible with SEH");
+    if (ErrorCount)
+      return;
+  }
+
+  // Windows specific -- when we are creating a .dll file, we also
+  // need to create a .lib file.
+  if (!Config->Exports.empty() || Config->DLL) {
+    fixupExports();
+    createImportLibrary(/*AsLib=*/false);
+    assignExportOrdinals();
+  }
+
+  // Windows specific -- Create a side-by-side manifest file.
+  if (Config->Manifest == Configuration::SideBySide)
+    createSideBySideManifest();
+
+  // Identify unreferenced COMDAT sections.
+  if (Config->DoGC)
+    markLive(Symtab.getChunks());
+
+  // Identify identical COMDAT sections to merge them.
+  if (Config->DoICF)
+    doICF(Symtab.getChunks());
+
+  // Write the result.
+  writeResult(&Symtab);
+
+  // Call exit to avoid calling destructors.
+  exit(0);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Driver.h b/COFF/Driver.h
new file mode 100644 (file)
index 0000000..6879be2
--- /dev/null
@@ -0,0 +1,188 @@
+//===- Driver.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_DRIVER_H
+#define LLD_COFF_DRIVER_H
+
+#include "Config.h"
+#include "SymbolTable.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reproduce.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/TarWriter.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+class LinkerDriver;
+extern LinkerDriver *Driver;
+
+using llvm::COFF::MachineTypes;
+using llvm::COFF::WindowsSubsystem;
+using llvm::Optional;
+
+// Implemented in MarkLive.cpp.
+void markLive(const std::vector<Chunk *> &Chunks);
+
+// Implemented in ICF.cpp.
+void doICF(const std::vector<Chunk *> &Chunks);
+
+class ArgParser {
+public:
+  // Parses command line options.
+  llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
+
+  // Concatenate LINK environment varirable and given arguments and parse them.
+  llvm::opt::InputArgList parseLINK(std::vector<const char *> Args);
+
+  // Tokenizes a given string and then parses as command line options.
+  llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
+
+private:
+  std::vector<const char *> tokenize(StringRef S);
+
+  std::vector<const char *> replaceResponseFiles(std::vector<const char *>);
+};
+
+class LinkerDriver {
+public:
+  LinkerDriver() { coff::Symtab = &Symtab; }
+  void link(llvm::ArrayRef<const char *> Args);
+
+  // Used by the resolver to parse .drectve section contents.
+  void parseDirectives(StringRef S);
+
+  // Used by ArchiveFile to enqueue members.
+  void enqueueArchiveMember(const Archive::Child &C, StringRef SymName,
+                            StringRef ParentName);
+
+private:
+  ArgParser Parser;
+  SymbolTable Symtab;
+
+  std::unique_ptr<llvm::TarWriter> Tar; // for /linkrepro
+
+  // Opens a file. Path has to be resolved already.
+  MemoryBufferRef openFile(StringRef Path);
+
+  // Searches a file from search paths.
+  Optional<StringRef> findFile(StringRef Filename);
+  Optional<StringRef> findLib(StringRef Filename);
+  StringRef doFindFile(StringRef Filename);
+  StringRef doFindLib(StringRef Filename);
+
+  // Parses LIB environment which contains a list of search paths.
+  void addLibSearchPaths();
+
+  // Library search path. The first element is always "" (current directory).
+  std::vector<StringRef> SearchPaths;
+  std::set<std::string> VisitedFiles;
+  std::set<std::string> VisitedLibs;
+
+  SymbolBody *addUndefined(StringRef Sym);
+  StringRef mangle(StringRef Sym);
+
+  // Windows specific -- "main" is not the only main function in Windows.
+  // You can choose one from these four -- {w,}{WinMain,main}.
+  // There are four different entry point functions for them,
+  // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to
+  // choose the right one depending on which "main" function is defined.
+  // This function looks up the symbol table and resolve corresponding
+  // entry point name.
+  StringRef findDefaultEntry();
+  WindowsSubsystem inferSubsystem();
+
+  void invokeMSVC(llvm::opt::InputArgList &Args);
+
+  MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
+  void addBuffer(std::unique_ptr<MemoryBuffer> MB);
+  void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
+                        StringRef ParentName);
+
+  void enqueuePath(StringRef Path);
+
+  void enqueueTask(std::function<void()> Task);
+  bool run();
+
+  std::list<std::function<void()>> TaskQueue;
+  std::vector<StringRef> FilePaths;
+  std::vector<MemoryBufferRef> Resources;
+};
+
+// Functions below this line are defined in DriverUtils.cpp.
+
+void printHelp(const char *Argv0);
+
+// For /machine option.
+MachineTypes getMachineType(StringRef Arg);
+StringRef machineToStr(MachineTypes MT);
+
+// Parses a string in the form of "<integer>[,<integer>]".
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// Minor's default value is 0.
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+                    uint32_t *Minor);
+
+void parseAlternateName(StringRef);
+void parseMerge(StringRef);
+void parseSection(StringRef);
+
+// Parses a string in the form of "EMBED[,=<integer>]|NO".
+void parseManifest(StringRef Arg);
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>"
+void parseManifestUAC(StringRef Arg);
+
+// Create a resource file containing a manifest XML.
+std::unique_ptr<MemoryBuffer> createManifestRes();
+void createSideBySideManifest();
+
+// Used for dllexported symbols.
+Export parseExport(StringRef Arg);
+void fixupExports();
+void assignExportOrdinals();
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the key.
+// This feature used in the directive section to reject
+// incompatible objects.
+void checkFailIfMismatch(StringRef Arg);
+
+// Convert Windows resource files (.res files) to a .obj file
+// using cvtres.exe.
+std::unique_ptr<MemoryBuffer>
+convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
+
+void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects);
+
+// Create enum with OPT_xxx values for each option in Options.td
+enum {
+  OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
new file mode 100644 (file)
index 0000000..39d5824
--- /dev/null
@@ -0,0 +1,730 @@
+//===- DriverUtils.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the driver. Because there
+// are so many small functions, we created this separate file to make
+// Driver.cpp less cluttered.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "Memory.h"
+#include "Symbols.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+
+using namespace llvm::COFF;
+using namespace llvm;
+using llvm::cl::ExpandResponseFiles;
+using llvm::cl::TokenizeWindowsCommandLine;
+using llvm::sys::Process;
+
+namespace lld {
+namespace coff {
+namespace {
+
+const uint16_t SUBLANG_ENGLISH_US = 0x0409;
+const uint16_t RT_MANIFEST = 24;
+
+class Executor {
+public:
+  explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
+  void add(StringRef S) { Args.push_back(Saver.save(S)); }
+  void add(std::string &S) { Args.push_back(Saver.save(S)); }
+  void add(Twine S) { Args.push_back(Saver.save(S)); }
+  void add(const char *S) { Args.push_back(Saver.save(S)); }
+
+  void run() {
+    ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog);
+    if (auto EC = ExeOrErr.getError())
+      fatal(EC, "unable to find " + Prog + " in PATH: ");
+    StringRef Exe = Saver.save(*ExeOrErr);
+    Args.insert(Args.begin(), Exe);
+
+    std::vector<const char *> Vec;
+    for (StringRef S : Args)
+      Vec.push_back(S.data());
+    Vec.push_back(nullptr);
+
+    if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0)
+      fatal("ExecuteAndWait failed: " +
+            llvm::join(Args.begin(), Args.end(), " "));
+  }
+
+private:
+  StringRef Prog;
+  std::vector<StringRef> Args;
+};
+
+} // anonymous namespace
+
+// Returns /machine's value.
+MachineTypes getMachineType(StringRef S) {
+  MachineTypes MT = StringSwitch<MachineTypes>(S.lower())
+                        .Cases("x64", "amd64", AMD64)
+                        .Cases("x86", "i386", I386)
+                        .Case("arm", ARMNT)
+                        .Case("arm64", ARM64)
+                        .Default(IMAGE_FILE_MACHINE_UNKNOWN);
+  if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
+    return MT;
+  fatal("unknown /machine argument: " + S);
+}
+
+StringRef machineToStr(MachineTypes MT) {
+  switch (MT) {
+  case ARMNT:
+    return "arm";
+  case ARM64:
+    return "arm64";
+  case AMD64:
+    return "x64";
+  case I386:
+    return "x86";
+  default:
+    llvm_unreachable("unknown machine type");
+  }
+}
+
+// Parses a string in the form of "<integer>[,<integer>]".
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
+  StringRef S1, S2;
+  std::tie(S1, S2) = Arg.split(',');
+  if (S1.getAsInteger(0, *Addr))
+    fatal("invalid number: " + S1);
+  if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
+    fatal("invalid number: " + S2);
+}
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// If second number is not present, Minor is set to 0.
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
+  StringRef S1, S2;
+  std::tie(S1, S2) = Arg.split('.');
+  if (S1.getAsInteger(0, *Major))
+    fatal("invalid number: " + S1);
+  *Minor = 0;
+  if (!S2.empty() && S2.getAsInteger(0, *Minor))
+    fatal("invalid number: " + S2);
+}
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+                    uint32_t *Minor) {
+  StringRef SysStr, Ver;
+  std::tie(SysStr, Ver) = Arg.split(',');
+  *Sys = StringSwitch<WindowsSubsystem>(SysStr.lower())
+    .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
+    .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
+    .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)
+    .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
+    .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)
+    .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
+    .Case("native", IMAGE_SUBSYSTEM_NATIVE)
+    .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
+    .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
+    .Default(IMAGE_SUBSYSTEM_UNKNOWN);
+  if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
+    fatal("unknown subsystem: " + SysStr);
+  if (!Ver.empty())
+    parseVersion(Ver, Major, Minor);
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseAlternateName(StringRef S) {
+  StringRef From, To;
+  std::tie(From, To) = S.split('=');
+  if (From.empty() || To.empty())
+    fatal("/alternatename: invalid argument: " + S);
+  auto It = Config->AlternateNames.find(From);
+  if (It != Config->AlternateNames.end() && It->second != To)
+    fatal("/alternatename: conflicts: " + S);
+  Config->AlternateNames.insert(It, std::make_pair(From, To));
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseMerge(StringRef S) {
+  StringRef From, To;
+  std::tie(From, To) = S.split('=');
+  if (From.empty() || To.empty())
+    fatal("/merge: invalid argument: " + S);
+  auto Pair = Config->Merge.insert(std::make_pair(From, To));
+  bool Inserted = Pair.second;
+  if (!Inserted) {
+    StringRef Existing = Pair.first->second;
+    if (Existing != To)
+      warn(S + ": already merged into " + Existing);
+  }
+}
+
+static uint32_t parseSectionAttributes(StringRef S) {
+  uint32_t Ret = 0;
+  for (char C : S.lower()) {
+    switch (C) {
+    case 'd':
+      Ret |= IMAGE_SCN_MEM_DISCARDABLE;
+      break;
+    case 'e':
+      Ret |= IMAGE_SCN_MEM_EXECUTE;
+      break;
+    case 'k':
+      Ret |= IMAGE_SCN_MEM_NOT_CACHED;
+      break;
+    case 'p':
+      Ret |= IMAGE_SCN_MEM_NOT_PAGED;
+      break;
+    case 'r':
+      Ret |= IMAGE_SCN_MEM_READ;
+      break;
+    case 's':
+      Ret |= IMAGE_SCN_MEM_SHARED;
+      break;
+    case 'w':
+      Ret |= IMAGE_SCN_MEM_WRITE;
+      break;
+    default:
+      fatal("/section: invalid argument: " + S);
+    }
+  }
+  return Ret;
+}
+
+// Parses /section option argument.
+void parseSection(StringRef S) {
+  StringRef Name, Attrs;
+  std::tie(Name, Attrs) = S.split(',');
+  if (Name.empty() || Attrs.empty())
+    fatal("/section: invalid argument: " + S);
+  Config->Section[Name] = parseSectionAttributes(Attrs);
+}
+
+// Parses a string in the form of "EMBED[,=<integer>]|NO".
+// Results are directly written to Config.
+void parseManifest(StringRef Arg) {
+  if (Arg.equals_lower("no")) {
+    Config->Manifest = Configuration::No;
+    return;
+  }
+  if (!Arg.startswith_lower("embed"))
+    fatal("invalid option " + Arg);
+  Config->Manifest = Configuration::Embed;
+  Arg = Arg.substr(strlen("embed"));
+  if (Arg.empty())
+    return;
+  if (!Arg.startswith_lower(",id="))
+    fatal("invalid option " + Arg);
+  Arg = Arg.substr(strlen(",id="));
+  if (Arg.getAsInteger(0, Config->ManifestID))
+    fatal("invalid option " + Arg);
+}
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
+// Results are directly written to Config.
+void parseManifestUAC(StringRef Arg) {
+  if (Arg.equals_lower("no")) {
+    Config->ManifestUAC = false;
+    return;
+  }
+  for (;;) {
+    Arg = Arg.ltrim();
+    if (Arg.empty())
+      return;
+    if (Arg.startswith_lower("level=")) {
+      Arg = Arg.substr(strlen("level="));
+      std::tie(Config->ManifestLevel, Arg) = Arg.split(" ");
+      continue;
+    }
+    if (Arg.startswith_lower("uiaccess=")) {
+      Arg = Arg.substr(strlen("uiaccess="));
+      std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" ");
+      continue;
+    }
+    fatal("invalid option " + Arg);
+  }
+}
+
+// An RAII temporary file class that automatically removes a temporary file.
+namespace {
+class TemporaryFile {
+public:
+  TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
+    SmallString<128> S;
+    if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
+      fatal(EC, "cannot create a temporary file");
+    Path = S.str();
+
+    if (!Contents.empty()) {
+      std::error_code EC;
+      raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+      if (EC)
+        fatal(EC, "failed to open " + Path);
+      OS << Contents;
+    }
+  }
+
+  TemporaryFile(TemporaryFile &&Obj) {
+    std::swap(Path, Obj.Path);
+  }
+
+  ~TemporaryFile() {
+    if (Path.empty())
+      return;
+    if (sys::fs::remove(Path))
+      fatal("failed to remove " + Path);
+  }
+
+  // Returns a memory buffer of this temporary file.
+  // Note that this function does not leave the file open,
+  // so it is safe to remove the file immediately after this function
+  // is called (you cannot remove an opened file on Windows.)
+  std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
+    // IsVolatileSize=true forces MemoryBuffer to not use mmap().
+    return check(MemoryBuffer::getFile(Path, /*FileSize=*/-1,
+                                       /*RequiresNullTerminator=*/false,
+                                       /*IsVolatileSize=*/true),
+                 "could not open " + Path);
+  }
+
+  std::string Path;
+};
+}
+
+// Create the default manifest file as a temporary file.
+TemporaryFile createDefaultXml() {
+  // Create a temporary file.
+  TemporaryFile File("defaultxml", "manifest");
+
+  // Open the temporary file for writing.
+  std::error_code EC;
+  raw_fd_ostream OS(File.Path, EC, sys::fs::F_Text);
+  if (EC)
+    fatal(EC, "failed to open " + File.Path);
+
+  // Emit the XML. Note that we do *not* verify that the XML attributes are
+  // syntactically correct. This is intentional for link.exe compatibility.
+  OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
+     << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
+     << "          manifestVersion=\"1.0\">\n";
+  if (Config->ManifestUAC) {
+    OS << "  <trustInfo>\n"
+       << "    <security>\n"
+       << "      <requestedPrivileges>\n"
+       << "         <requestedExecutionLevel level=" << Config->ManifestLevel
+       << " uiAccess=" << Config->ManifestUIAccess << "/>\n"
+       << "      </requestedPrivileges>\n"
+       << "    </security>\n"
+       << "  </trustInfo>\n";
+    if (!Config->ManifestDependency.empty()) {
+      OS << "  <dependency>\n"
+         << "    <dependentAssembly>\n"
+         << "      <assemblyIdentity " << Config->ManifestDependency << " />\n"
+         << "    </dependentAssembly>\n"
+         << "  </dependency>\n";
+    }
+  }
+  OS << "</assembly>\n";
+  OS.close();
+  return File;
+}
+
+static std::string readFile(StringRef Path) {
+  std::unique_ptr<MemoryBuffer> MB =
+      check(MemoryBuffer::getFile(Path), "could not open " + Path);
+  return MB->getBuffer();
+}
+
+static std::string createManifestXml() {
+  // Create the default manifest file.
+  TemporaryFile File1 = createDefaultXml();
+  if (Config->ManifestInput.empty())
+    return readFile(File1.Path);
+
+  // If manifest files are supplied by the user using /MANIFESTINPUT
+  // option, we need to merge them with the default manifest.
+  TemporaryFile File2("user", "manifest");
+
+  Executor E("mt.exe");
+  E.add("/manifest");
+  E.add(File1.Path);
+  for (StringRef Filename : Config->ManifestInput) {
+    E.add("/manifest");
+    E.add(Filename);
+  }
+  E.add("/nologo");
+  E.add("/out:" + StringRef(File2.Path));
+  E.run();
+  return readFile(File2.Path);
+}
+
+static std::unique_ptr<MemoryBuffer>
+createMemoryBufferForManifestRes(size_t ManifestSize) {
+  size_t ResSize = alignTo(
+      object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
+          sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
+          sizeof(object::WinResHeaderSuffix) + ManifestSize,
+      object::WIN_RES_DATA_ALIGNMENT);
+  return MemoryBuffer::getNewMemBuffer(ResSize);
+}
+
+static void writeResFileHeader(char *&Buf) {
+  memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
+  Buf += sizeof(COFF::WinResMagic);
+  memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
+  Buf += object::WIN_RES_NULL_ENTRY_SIZE;
+}
+
+static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
+  // Write the prefix.
+  auto *Prefix = reinterpret_cast<object::WinResHeaderPrefix *>(Buf);
+  Prefix->DataSize = ManifestSize;
+  Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
+                       sizeof(object::WinResIDs) +
+                       sizeof(object::WinResHeaderSuffix);
+  Buf += sizeof(object::WinResHeaderPrefix);
+
+  // Write the Type/Name IDs.
+  auto *IDs = reinterpret_cast<object::WinResIDs *>(Buf);
+  IDs->setType(RT_MANIFEST);
+  IDs->setName(Config->ManifestID);
+  Buf += sizeof(object::WinResIDs);
+
+  // Write the suffix.
+  auto *Suffix = reinterpret_cast<object::WinResHeaderSuffix *>(Buf);
+  Suffix->DataVersion = 0;
+  Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
+  Suffix->Language = SUBLANG_ENGLISH_US;
+  Suffix->Version = 0;
+  Suffix->Characteristics = 0;
+  Buf += sizeof(object::WinResHeaderSuffix);
+}
+
+// Create a resource file containing a manifest XML.
+std::unique_ptr<MemoryBuffer> createManifestRes() {
+  std::string Manifest = createManifestXml();
+
+  std::unique_ptr<MemoryBuffer> Res =
+      createMemoryBufferForManifestRes(Manifest.size());
+
+  char *Buf = const_cast<char *>(Res->getBufferStart());
+  writeResFileHeader(Buf);
+  writeResEntryHeader(Buf, Manifest.size());
+
+  // Copy the manifest data into the .res file.
+  std::copy(Manifest.begin(), Manifest.end(), Buf);
+  return Res;
+}
+
+void createSideBySideManifest() {
+  std::string Path = Config->ManifestFile;
+  if (Path == "")
+    Path = Config->OutputFile + ".manifest";
+  std::error_code EC;
+  raw_fd_ostream Out(Path, EC, sys::fs::F_Text);
+  if (EC)
+    fatal(EC, "failed to create manifest");
+  Out << createManifestXml();
+}
+
+// Parse a string in the form of
+// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
+// or "<name>=<dllname>.<name>".
+// Used for parsing /export arguments.
+Export parseExport(StringRef Arg) {
+  Export E;
+  StringRef Rest;
+  std::tie(E.Name, Rest) = Arg.split(",");
+  if (E.Name.empty())
+    goto err;
+
+  if (E.Name.find('=') != StringRef::npos) {
+    StringRef X, Y;
+    std::tie(X, Y) = E.Name.split("=");
+
+    // If "<name>=<dllname>.<name>".
+    if (Y.find(".") != StringRef::npos) {
+      E.Name = X;
+      E.ForwardTo = Y;
+      return E;
+    }
+
+    E.ExtName = X;
+    E.Name = Y;
+    if (E.Name.empty())
+      goto err;
+  }
+
+  // If "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
+  while (!Rest.empty()) {
+    StringRef Tok;
+    std::tie(Tok, Rest) = Rest.split(",");
+    if (Tok.equals_lower("noname")) {
+      if (E.Ordinal == 0)
+        goto err;
+      E.Noname = true;
+      continue;
+    }
+    if (Tok.equals_lower("data")) {
+      E.Data = true;
+      continue;
+    }
+    if (Tok.equals_lower("constant")) {
+      E.Constant = true;
+      continue;
+    }
+    if (Tok.equals_lower("private")) {
+      E.Private = true;
+      continue;
+    }
+    if (Tok.startswith("@")) {
+      int32_t Ord;
+      if (Tok.substr(1).getAsInteger(0, Ord))
+        goto err;
+      if (Ord <= 0 || 65535 < Ord)
+        goto err;
+      E.Ordinal = Ord;
+      continue;
+    }
+    goto err;
+  }
+  return E;
+
+err:
+  fatal("invalid /export: " + Arg);
+}
+
+static StringRef undecorate(StringRef Sym) {
+  if (Config->Machine != I386)
+    return Sym;
+  return Sym.startswith("_") ? Sym.substr(1) : Sym;
+}
+
+// Performs error checking on all /export arguments.
+// It also sets ordinals.
+void fixupExports() {
+  // Symbol ordinals must be unique.
+  std::set<uint16_t> Ords;
+  for (Export &E : Config->Exports) {
+    if (E.Ordinal == 0)
+      continue;
+    if (!Ords.insert(E.Ordinal).second)
+      fatal("duplicate export ordinal: " + E.Name);
+  }
+
+  for (Export &E : Config->Exports) {
+    SymbolBody *Sym = E.Sym;
+    if (!E.ForwardTo.empty() || !Sym) {
+      E.SymbolName = E.Name;
+    } else {
+      if (auto *U = dyn_cast<Undefined>(Sym))
+        if (U->WeakAlias)
+          Sym = U->WeakAlias;
+      E.SymbolName = Sym->getName();
+    }
+  }
+
+  for (Export &E : Config->Exports) {
+    if (!E.ForwardTo.empty()) {
+      E.ExportName = undecorate(E.Name);
+    } else {
+      E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName);
+    }
+  }
+
+  // Uniquefy by name.
+  std::map<StringRef, Export *> Map;
+  std::vector<Export> V;
+  for (Export &E : Config->Exports) {
+    auto Pair = Map.insert(std::make_pair(E.ExportName, &E));
+    bool Inserted = Pair.second;
+    if (Inserted) {
+      V.push_back(E);
+      continue;
+    }
+    Export *Existing = Pair.first->second;
+    if (E == *Existing || E.Name != Existing->Name)
+      continue;
+    warn("duplicate /export option: " + E.Name);
+  }
+  Config->Exports = std::move(V);
+
+  // Sort by name.
+  std::sort(Config->Exports.begin(), Config->Exports.end(),
+            [](const Export &A, const Export &B) {
+              return A.ExportName < B.ExportName;
+            });
+}
+
+void assignExportOrdinals() {
+  // Assign unique ordinals if default (= 0).
+  uint16_t Max = 0;
+  for (Export &E : Config->Exports)
+    Max = std::max(Max, E.Ordinal);
+  for (Export &E : Config->Exports)
+    if (E.Ordinal == 0)
+      E.Ordinal = ++Max;
+}
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the same key.
+void checkFailIfMismatch(StringRef Arg) {
+  StringRef K, V;
+  std::tie(K, V) = Arg.split('=');
+  if (K.empty() || V.empty())
+    fatal("/failifmismatch: invalid argument: " + Arg);
+  StringRef Existing = Config->MustMatch[K];
+  if (!Existing.empty() && V != Existing)
+    fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V +
+          " for key " + K);
+  Config->MustMatch[K] = V;
+}
+
+// Convert Windows resource files (.res files) to a .obj file
+// using cvtres.exe.
+std::unique_ptr<MemoryBuffer>
+convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
+  object::WindowsResourceParser Parser;
+
+  for (MemoryBufferRef MB : MBs) {
+    std::unique_ptr<object::Binary> Bin = check(object::createBinary(MB));
+    object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get());
+    if (!RF)
+      fatal("cannot compile non-resource file as resource");
+    if (auto EC = Parser.parse(RF))
+      fatal(EC, "failed to parse .res file");
+  }
+
+  Expected<std::unique_ptr<MemoryBuffer>> E =
+      llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser);
+  if (!E)
+    fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF");
+  return std::move(E.get());
+}
+
+// Run MSVC link.exe for given in-memory object files.
+// Command line options are copied from those given to LLD.
+// This is for the /msvclto option.
+void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects) {
+  // Write the in-memory object files to disk.
+  std::vector<TemporaryFile> Temps;
+  for (StringRef S : Objects) {
+    Temps.emplace_back("lto", "obj", S);
+    Rsp += quote(Temps.back().Path) + "\n";
+  }
+
+  log("link.exe " + Rsp);
+
+  // Run MSVC link.exe.
+  Temps.emplace_back("lto", "rsp", Rsp);
+  Executor E("link.exe");
+  E.add(Twine("@" + Temps.back().Path));
+  E.run();
+}
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
+  {X1, X2, X10,         X11,         OPT_##ID, llvm::opt::Option::KIND##Class, \
+   X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
+#include "Options.inc"
+#undef OPTION
+};
+
+class COFFOptTable : public llvm::opt::OptTable {
+public:
+  COFFOptTable() : OptTable(infoTable, true) {}
+};
+
+// Parses a given list of options.
+opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
+  // First, replace respnose files (@<file>-style options).
+  std::vector<const char *> Argv = replaceResponseFiles(ArgsArr);
+
+  // Make InputArgList from string vectors.
+  COFFOptTable Table;
+  unsigned MissingIndex;
+  unsigned MissingCount;
+  opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
+
+  // Print the real command line if response files are expanded.
+  if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) {
+    std::string Msg = "Command line:";
+    for (const char *S : Argv)
+      Msg += " " + std::string(S);
+    message(Msg);
+  }
+
+  if (MissingCount)
+    fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+    warn("ignoring unknown argument: " + Arg->getSpelling());
+  return Args;
+}
+
+// link.exe has an interesting feature. If LINK or _LINK_ environment
+// variables exist, their contents are handled as command line strings.
+// So you can pass extra arguments using them.
+opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Args) {
+  // Concatenate LINK env and command line arguments, and then parse them.
+  if (Optional<std::string> S = Process::GetEnv("LINK")) {
+    std::vector<const char *> V = tokenize(*S);
+    Args.insert(Args.begin(), V.begin(), V.end());
+  }
+  if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
+    std::vector<const char *> V = tokenize(*S);
+    Args.insert(Args.begin(), V.begin(), V.end());
+  }
+  return parse(Args);
+}
+
+std::vector<const char *> ArgParser::tokenize(StringRef S) {
+  SmallVector<const char *, 16> Tokens;
+  cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
+  return std::vector<const char *>(Tokens.begin(), Tokens.end());
+}
+
+// Creates a new command line by replacing options starting with '@'
+// character. '@<filename>' is replaced by the file's contents.
+std::vector<const char *>
+ArgParser::replaceResponseFiles(std::vector<const char *> Argv) {
+  SmallVector<const char *, 256> Tokens(Argv.data(), Argv.data() + Argv.size());
+  ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens);
+  return std::vector<const char *>(Tokens.begin(), Tokens.end());
+}
+
+void printHelp(const char *Argv0) {
+  COFFOptTable Table;
+  Table.PrintHelp(outs(), Argv0, "LLVM Linker", false);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Error.cpp b/COFF/Error.cpp
new file mode 100644 (file)
index 0000000..34abc28
--- /dev/null
@@ -0,0 +1,114 @@
+//===- Error.cpp ----------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Config.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+#include <mutex>
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#endif
+
+using namespace llvm;
+
+namespace lld {
+// The functions defined in this file can be called from multiple threads,
+// but outs() or errs() are not thread-safe. We protect them using a mutex.
+static std::mutex Mu;
+
+namespace coff {
+uint64_t ErrorCount;
+raw_ostream *ErrorOS;
+
+static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
+  // Dealloc/destroy ManagedStatic variables before calling
+  // _exit(). In a non-LTO build, this is a nop. In an LTO
+  // build allows us to get the output of -time-passes.
+  llvm_shutdown();
+
+  outs().flush();
+  errs().flush();
+  _exit(Val);
+}
+
+static void print(StringRef S, raw_ostream::Colors C) {
+  *ErrorOS << Config->Argv[0] << ": ";
+  if (Config->ColorDiagnostics) {
+    ErrorOS->changeColor(C, true);
+    *ErrorOS << S;
+    ErrorOS->resetColor();
+  } else {
+    *ErrorOS << S;
+  }
+}
+
+void log(const Twine &Msg) {
+  if (Config->Verbose) {
+    std::lock_guard<std::mutex> Lock(Mu);
+    outs() << Config->Argv[0] << ": " << Msg << "\n";
+    outs().flush();
+  }
+}
+
+void message(const Twine &Msg) {
+  std::lock_guard<std::mutex> Lock(Mu);
+  outs() << Msg << "\n";
+  outs().flush();
+}
+
+void error(const Twine &Msg) {
+  std::lock_guard<std::mutex> Lock(Mu);
+
+  if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
+    print("error: ", raw_ostream::RED);
+    *ErrorOS << Msg << "\n";
+  } else if (ErrorCount == Config->ErrorLimit) {
+    print("error: ", raw_ostream::RED);
+    *ErrorOS << "too many errors emitted, stopping now"
+             << " (use /ERRORLIMIT:0 to see all errors)\n";
+    exitLld(1);
+  }
+
+  ++ErrorCount;
+}
+
+void fatal(const Twine &Msg) {
+  if (Config->ColorDiagnostics) {
+    errs().changeColor(raw_ostream::RED, /*bold=*/true);
+    errs() << "error: ";
+    errs().resetColor();
+  } else {
+    errs() << "error: ";
+  }
+  errs() << Msg << "\n";
+  exitLld(1);
+}
+
+void fatal(std::error_code EC, const Twine &Msg) {
+  fatal(Msg + ": " + EC.message());
+}
+
+void fatal(llvm::Error &Err, const Twine &Msg) {
+  fatal(errorToErrorCode(std::move(Err)), Msg);
+}
+
+void warn(const Twine &Msg) {
+  std::lock_guard<std::mutex> Lock(Mu);
+  print("warning: ", raw_ostream::MAGENTA);
+  *ErrorOS << Msg << "\n";
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Error.h b/COFF/Error.h
new file mode 100644 (file)
index 0000000..e1e4c1e
--- /dev/null
@@ -0,0 +1,62 @@
+//===- Error.h --------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_ERROR_H
+#define LLD_COFF_ERROR_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/Error.h"
+
+namespace lld {
+namespace coff {
+
+extern uint64_t ErrorCount;
+extern llvm::raw_ostream *ErrorOS;
+
+void log(const Twine &Msg);
+void message(const Twine &Msg);
+void warn(const Twine &Msg);
+void error(const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
+LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix);
+
+template <class T> T check(ErrorOr<T> V, const Twine &Prefix) {
+  if (auto EC = V.getError())
+    fatal(EC, Prefix);
+  return std::move(*V);
+}
+
+template <class T> T check(Expected<T> E, const Twine &Prefix) {
+  if (llvm::Error Err = E.takeError())
+    fatal(Err, Prefix);
+  return std::move(*E);
+}
+
+template <class T> T check(ErrorOr<T> EO) {
+  if (!EO)
+    fatal(EO.getError().message());
+  return std::move(*EO);
+}
+
+template <class T> T check(Expected<T> E) {
+  if (!E) {
+    std::string Buf;
+    llvm::raw_string_ostream OS(Buf);
+    logAllUnhandledErrors(E.takeError(), OS, "");
+    OS.flush();
+    fatal(Buf);
+  }
+  return std::move(*E);
+}
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
new file mode 100644 (file)
index 0000000..da8ca36
--- /dev/null
@@ -0,0 +1,258 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ICF is short for Identical Code Folding. That is a size optimization to
+// identify and merge two or more read-only sections (typically functions)
+// that happened to have the same contents. It usually reduces output size
+// by a few percent.
+//
+// On Windows, ICF is enabled by default.
+//
+// See ELF/ICF.cpp for the details about the algortihm.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Error.h"
+#include "Symbols.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <atomic>
+#include <vector>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+class ICF {
+public:
+  void run(const std::vector<Chunk *> &V);
+
+private:
+  void segregate(size_t Begin, size_t End, bool Constant);
+
+  bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
+  bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
+
+  uint32_t getHash(SectionChunk *C);
+  bool isEligible(SectionChunk *C);
+
+  size_t findBoundary(size_t Begin, size_t End);
+
+  void forEachClassRange(size_t Begin, size_t End,
+                         std::function<void(size_t, size_t)> Fn);
+
+  void forEachClass(std::function<void(size_t, size_t)> Fn);
+
+  std::vector<SectionChunk *> Chunks;
+  int Cnt = 0;
+  std::atomic<bool> Repeat = {false};
+};
+
+// Returns a hash value for S.
+uint32_t ICF::getHash(SectionChunk *C) {
+  return hash_combine(C->getPermissions(),
+                      hash_value(C->SectionName),
+                      C->NumRelocs,
+                      C->getAlign(),
+                      uint32_t(C->Header->SizeOfRawData),
+                      C->Checksum);
+}
+
+// Returns true if section S is subject of ICF.
+//
+// Microsoft's documentation
+// (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April
+// 2017) says that /opt:icf folds both functions and read-only data.
+// Despite that, the MSVC linker folds only functions. We found
+// a few instances of programs that are not safe for data merging.
+// Therefore, we merge only functions just like the MSVC tool.
+bool ICF::isEligible(SectionChunk *C) {
+  bool Global = C->Sym && C->Sym->isExternal();
+  bool Executable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE;
+  bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+  return C->isCOMDAT() && C->isLive() && Global && Executable && !Writable;
+}
+
+// Split an equivalence class into smaller classes.
+void ICF::segregate(size_t Begin, size_t End, bool Constant) {
+  while (Begin < End) {
+    // Divide [Begin, End) into two. Let Mid be the start index of the
+    // second group.
+    auto Bound = std::stable_partition(
+        Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) {
+          if (Constant)
+            return equalsConstant(Chunks[Begin], S);
+          return equalsVariable(Chunks[Begin], S);
+        });
+    size_t Mid = Bound - Chunks.begin();
+
+    // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an
+    // equivalence class ID because every group ends with a unique index.
+    for (size_t I = Begin; I < Mid; ++I)
+      Chunks[I]->Class[(Cnt + 1) % 2] = Mid;
+
+    // If we created a group, we need to iterate the main loop again.
+    if (Mid != End)
+      Repeat = true;
+
+    Begin = Mid;
+  }
+}
+
+// Compare "non-moving" part of two sections, namely everything
+// except relocation targets.
+bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
+  if (A->NumRelocs != B->NumRelocs)
+    return false;
+
+  // Compare relocations.
+  auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+    if (R1.Type != R2.Type ||
+        R1.VirtualAddress != R2.VirtualAddress) {
+      return false;
+    }
+    SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex);
+    SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex);
+    if (B1 == B2)
+      return true;
+    if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+      if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+        return D1->getValue() == D2->getValue() &&
+               D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
+    return false;
+  };
+  if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq))
+    return false;
+
+  // Compare section attributes and contents.
+  return A->getPermissions() == B->getPermissions() &&
+         A->SectionName == B->SectionName &&
+         A->getAlign() == B->getAlign() &&
+         A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
+         A->Checksum == B->Checksum &&
+         A->getContents() == B->getContents();
+}
+
+// Compare "moving" part of two sections, namely relocation targets.
+bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
+  // Compare relocations.
+  auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+    SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex);
+    SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex);
+    if (B1 == B2)
+      return true;
+    if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+      if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+        return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
+    return false;
+  };
+  return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
+}
+
+size_t ICF::findBoundary(size_t Begin, size_t End) {
+  for (size_t I = Begin + 1; I < End; ++I)
+    if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2])
+      return I;
+  return End;
+}
+
+void ICF::forEachClassRange(size_t Begin, size_t End,
+                            std::function<void(size_t, size_t)> Fn) {
+  if (Begin > 0)
+    Begin = findBoundary(Begin - 1, End);
+
+  while (Begin < End) {
+    size_t Mid = findBoundary(Begin, Chunks.size());
+    Fn(Begin, Mid);
+    Begin = Mid;
+  }
+}
+
+// Call Fn on each class group.
+void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
+  // If the number of sections are too small to use threading,
+  // call Fn sequentially.
+  if (Chunks.size() < 1024) {
+    forEachClassRange(0, Chunks.size(), Fn);
+    ++Cnt;
+    return;
+  }
+
+  // Split sections into 256 shards and call Fn in parallel.
+  size_t NumShards = 256;
+  size_t Step = Chunks.size() / NumShards;
+  for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) {
+    size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step;
+    forEachClassRange(I * Step, End, Fn);
+  });
+  ++Cnt;
+}
+
+// Merge identical COMDAT sections.
+// Two sections are considered the same if their section headers,
+// contents and relocations are all the same.
+void ICF::run(const std::vector<Chunk *> &Vec) {
+  // Collect only mergeable sections and group by hash value.
+  uint32_t NextId = 1;
+  for (Chunk *C : Vec) {
+    if (auto *SC = dyn_cast<SectionChunk>(C)) {
+      if (isEligible(SC))
+        Chunks.push_back(SC);
+      else
+        SC->Class[0] = NextId++;
+    }
+  }
+
+  // Initially, we use hash values to partition sections.
+  for (SectionChunk *SC : Chunks)
+    // Set MSB to 1 to avoid collisions with non-hash classs.
+    SC->Class[0] = getHash(SC) | (1 << 31);
+
+  // From now on, sections in Chunks are ordered so that sections in
+  // the same group are consecutive in the vector.
+  std::stable_sort(Chunks.begin(), Chunks.end(),
+                   [](SectionChunk *A, SectionChunk *B) {
+                     return A->Class[0] < B->Class[0];
+                   });
+
+  // Compare static contents and assign unique IDs for each static content.
+  forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
+
+  // Split groups by comparing relocations until convergence is obtained.
+  do {
+    Repeat = false;
+    forEachClass(
+        [&](size_t Begin, size_t End) { segregate(Begin, End, false); });
+  } while (Repeat);
+
+  log("ICF needed " + Twine(Cnt) + " iterations");
+
+  // Merge sections in the same classs.
+  forEachClass([&](size_t Begin, size_t End) {
+    if (End - Begin == 1)
+      return;
+
+    log("Selected " + Chunks[Begin]->getDebugName());
+    for (size_t I = Begin + 1; I < End; ++I) {
+      log("  Removed " + Chunks[I]->getDebugName());
+      Chunks[Begin]->replace(Chunks[I]);
+    }
+  });
+}
+
+// Entry point to ICF.
+void doICF(const std::vector<Chunk *> &Chunks) { ICF().run(Chunks); }
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
new file mode 100644 (file)
index 0000000..7d41cae
--- /dev/null
@@ -0,0 +1,411 @@
+//===- InputFiles.cpp -----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Chunks.h"
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "Memory.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "llvm-c/lto.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Target/TargetOptions.h"
+#include <cstring>
+#include <system_error>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using llvm::Triple;
+using llvm::support::ulittle32_t;
+
+namespace lld {
+namespace coff {
+
+/// Checks that Source is compatible with being a weak alias to Target.
+/// If Source is Undefined and has no weak alias set, makes it a weak
+/// alias to Target.
+static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
+                                 SymbolBody *Source, SymbolBody *Target) {
+  if (auto *U = dyn_cast<Undefined>(Source)) {
+    if (U->WeakAlias && U->WeakAlias != Target)
+      Symtab->reportDuplicate(Source->symbol(), F);
+    U->WeakAlias = Target;
+  }
+}
+
+ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+
+void ArchiveFile::parse() {
+  // Parse a MemoryBufferRef as an archive file.
+  File = check(Archive::create(MB), toString(this));
+
+  // Read the symbol table to construct Lazy objects.
+  for (const Archive::Symbol &Sym : File->symbols())
+    Symtab->addLazy(this, Sym);
+}
+
+// Returns a buffer pointing to a member file containing a given symbol.
+void ArchiveFile::addMember(const Archive::Symbol *Sym) {
+  const Archive::Child &C =
+      check(Sym->getMember(),
+            "could not get the member for symbol " + Sym->getName());
+
+  // Return an empty buffer if we have already returned the same buffer.
+  if (!Seen.insert(C.getChildOffset()).second)
+    return;
+
+  Driver->enqueueArchiveMember(C, Sym->getName(), getName());
+}
+
+void ObjectFile::parse() {
+  // Parse a memory buffer as a COFF file.
+  std::unique_ptr<Binary> Bin = check(createBinary(MB), toString(this));
+
+  if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) {
+    Bin.release();
+    COFFObj.reset(Obj);
+  } else {
+    fatal(toString(this) + " is not a COFF file");
+  }
+
+  // Read section and symbol tables.
+  initializeChunks();
+  initializeSymbols();
+  initializeSEH();
+}
+
+void ObjectFile::initializeChunks() {
+  uint32_t NumSections = COFFObj->getNumberOfSections();
+  Chunks.reserve(NumSections);
+  SparseChunks.resize(NumSections + 1);
+  for (uint32_t I = 1; I < NumSections + 1; ++I) {
+    const coff_section *Sec;
+    StringRef Name;
+    if (auto EC = COFFObj->getSection(I, Sec))
+      fatal(EC, "getSection failed: #" + Twine(I));
+    if (auto EC = COFFObj->getSectionName(Sec, Name))
+      fatal(EC, "getSectionName failed: #" + Twine(I));
+    if (Name == ".sxdata") {
+      SXData = Sec;
+      continue;
+    }
+    if (Name == ".drectve") {
+      ArrayRef<uint8_t> Data;
+      COFFObj->getSectionContents(Sec, Data);
+      Directives = std::string((const char *)Data.data(), Data.size());
+      continue;
+    }
+
+    // Object files may have DWARF debug info or MS CodeView debug info
+    // (or both).
+    //
+    // DWARF sections don't need any special handling from the perspective
+    // of the linker; they are just a data section containing relocations.
+    // We can just link them to complete debug info.
+    //
+    // CodeView needs a linker support. We need to interpret and debug
+    // info, and then write it to a separate .pdb file.
+
+    // Ignore debug info unless /debug is given.
+    if (!Config->Debug && Name.startswith(".debug"))
+      continue;
+
+    if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
+      continue;
+    auto *C = make<SectionChunk>(this, Sec);
+
+    // CodeView sections are stored to a different vector because they are not
+    // linked in the regular manner.
+    if (C->isCodeView())
+      DebugChunks.push_back(C);
+    else
+      Chunks.push_back(C);
+
+    SparseChunks[I] = C;
+  }
+}
+
+void ObjectFile::initializeSymbols() {
+  uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
+  SymbolBodies.reserve(NumSymbols);
+  SparseSymbolBodies.resize(NumSymbols);
+
+  SmallVector<std::pair<SymbolBody *, uint32_t>, 8> WeakAliases;
+  int32_t LastSectionNumber = 0;
+
+  for (uint32_t I = 0; I < NumSymbols; ++I) {
+    // Get a COFFSymbolRef object.
+    ErrorOr<COFFSymbolRef> SymOrErr = COFFObj->getSymbol(I);
+    if (!SymOrErr)
+      fatal(SymOrErr.getError(), "broken object file: " + toString(this));
+    COFFSymbolRef Sym = *SymOrErr;
+
+    const void *AuxP = nullptr;
+    if (Sym.getNumberOfAuxSymbols())
+      AuxP = COFFObj->getSymbol(I + 1)->getRawPtr();
+    bool IsFirst = (LastSectionNumber != Sym.getSectionNumber());
+
+    SymbolBody *Body = nullptr;
+    if (Sym.isUndefined()) {
+      Body = createUndefined(Sym);
+    } else if (Sym.isWeakExternal()) {
+      Body = createUndefined(Sym);
+      uint32_t TagIndex =
+          static_cast<const coff_aux_weak_external *>(AuxP)->TagIndex;
+      WeakAliases.emplace_back(Body, TagIndex);
+    } else {
+      Body = createDefined(Sym, AuxP, IsFirst);
+    }
+    if (Body) {
+      SymbolBodies.push_back(Body);
+      SparseSymbolBodies[I] = Body;
+    }
+    I += Sym.getNumberOfAuxSymbols();
+    LastSectionNumber = Sym.getSectionNumber();
+  }
+
+  for (auto &KV : WeakAliases) {
+    SymbolBody *Sym = KV.first;
+    uint32_t Idx = KV.second;
+    checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]);
+  }
+}
+
+SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) {
+  StringRef Name;
+  COFFObj->getSymbolName(Sym, Name);
+  return Symtab->addUndefined(Name, this, Sym.isWeakExternal())->body();
+}
+
+SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
+                                      bool IsFirst) {
+  StringRef Name;
+  if (Sym.isCommon()) {
+    auto *C = make<CommonChunk>(Sym);
+    Chunks.push_back(C);
+    COFFObj->getSymbolName(Sym, Name);
+    Symbol *S =
+        Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C);
+    return S->body();
+  }
+  if (Sym.isAbsolute()) {
+    COFFObj->getSymbolName(Sym, Name);
+    // Skip special symbols.
+    if (Name == "@comp.id")
+      return nullptr;
+    // COFF spec 5.10.1. The .sxdata section.
+    if (Name == "@feat.00") {
+      if (Sym.getValue() & 1)
+        SEHCompat = true;
+      return nullptr;
+    }
+    if (Sym.isExternal())
+      return Symtab->addAbsolute(Name, Sym)->body();
+    else
+      return make<DefinedAbsolute>(Name, Sym);
+  }
+  int32_t SectionNumber = Sym.getSectionNumber();
+  if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
+    return nullptr;
+
+  // Reserved sections numbers don't have contents.
+  if (llvm::COFF::isReservedSectionNumber(SectionNumber))
+    fatal("broken object file: " + toString(this));
+
+  // This symbol references a section which is not present in the section
+  // header.
+  if ((uint32_t)SectionNumber >= SparseChunks.size())
+    fatal("broken object file: " + toString(this));
+
+  // Nothing else to do without a section chunk.
+  auto *SC = cast_or_null<SectionChunk>(SparseChunks[SectionNumber]);
+  if (!SC)
+    return nullptr;
+
+  // Handle section definitions
+  if (IsFirst && AuxP) {
+    auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP);
+    if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+      if (auto *ParentSC = cast_or_null<SectionChunk>(
+              SparseChunks[Aux->getNumber(Sym.isBigObj())])) {
+        ParentSC->addAssociative(SC);
+        // If we already discarded the parent, discard the child.
+        if (ParentSC->isDiscarded())
+          SC->markDiscarded();
+      }
+    SC->Checksum = Aux->CheckSum;
+  }
+
+  DefinedRegular *B;
+  if (Sym.isExternal()) {
+    COFFObj->getSymbolName(Sym, Name);
+    Symbol *S =
+        Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC);
+    B = cast<DefinedRegular>(S->body());
+  } else
+    B = make<DefinedRegular>(this, /*Name*/ "", SC->isCOMDAT(),
+                             /*IsExternal*/ false, Sym.getGeneric(), SC);
+  if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
+    SC->setSymbol(B);
+
+  return B;
+}
+
+void ObjectFile::initializeSEH() {
+  if (!SEHCompat || !SXData)
+    return;
+  ArrayRef<uint8_t> A;
+  COFFObj->getSectionContents(SXData, A);
+  if (A.size() % 4 != 0)
+    fatal(".sxdata must be an array of symbol table indices");
+  auto *I = reinterpret_cast<const ulittle32_t *>(A.data());
+  auto *E = reinterpret_cast<const ulittle32_t *>(A.data() + A.size());
+  for (; I != E; ++I)
+    SEHandlers.insert(SparseSymbolBodies[*I]);
+}
+
+MachineTypes ObjectFile::getMachineType() {
+  if (COFFObj)
+    return static_cast<MachineTypes>(COFFObj->getMachine());
+  return IMAGE_FILE_MACHINE_UNKNOWN;
+}
+
+StringRef ltrim1(StringRef S, const char *Chars) {
+  if (!S.empty() && strchr(Chars, S[0]))
+    return S.substr(1);
+  return S;
+}
+
+void ImportFile::parse() {
+  const char *Buf = MB.getBufferStart();
+  const char *End = MB.getBufferEnd();
+  const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf);
+
+  // Check if the total size is valid.
+  if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData))
+    fatal("broken import library");
+
+  // Read names and create an __imp_ symbol.
+  StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr)));
+  StringRef ImpName = Saver.save("__imp_" + Name);
+  const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
+  DLLName = StringRef(NameStart);
+  StringRef ExtName;
+  switch (Hdr->getNameType()) {
+  case IMPORT_ORDINAL:
+    ExtName = "";
+    break;
+  case IMPORT_NAME:
+    ExtName = Name;
+    break;
+  case IMPORT_NAME_NOPREFIX:
+    ExtName = ltrim1(Name, "?@_");
+    break;
+  case IMPORT_NAME_UNDECORATE:
+    ExtName = ltrim1(Name, "?@_");
+    ExtName = ExtName.substr(0, ExtName.find('@'));
+    break;
+  }
+
+  this->Hdr = Hdr;
+  ExternalName = ExtName;
+
+  ImpSym = cast<DefinedImportData>(
+      Symtab->addImportData(ImpName, this)->body());
+  if (Hdr->getType() == llvm::COFF::IMPORT_CONST)
+    ConstSym =
+        cast<DefinedImportData>(Symtab->addImportData(Name, this)->body());
+
+  // If type is function, we need to create a thunk which jump to an
+  // address pointed by the __imp_ symbol. (This allows you to call
+  // DLL functions just like regular non-DLL functions.)
+  if (Hdr->getType() != llvm::COFF::IMPORT_CODE)
+    return;
+  ThunkSym = cast<DefinedImportThunk>(
+      Symtab->addImportThunk(Name, ImpSym, Hdr->Machine)->body());
+}
+
+void BitcodeFile::parse() {
+  Obj = check(lto::InputFile::create(MemoryBufferRef(
+      MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier()))));
+  for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) {
+    StringRef SymName = Saver.save(ObjSym.getName());
+    Symbol *Sym;
+    if (ObjSym.isUndefined()) {
+      Sym = Symtab->addUndefined(SymName, this, false);
+    } else if (ObjSym.isCommon()) {
+      Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize());
+    } else if (ObjSym.isWeak() && ObjSym.isIndirect()) {
+      // Weak external.
+      Sym = Symtab->addUndefined(SymName, this, true);
+      std::string Fallback = ObjSym.getCOFFWeakExternalFallback();
+      SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback));
+      checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias);
+    } else {
+      bool IsCOMDAT = ObjSym.getComdatIndex() != -1;
+      Sym = Symtab->addRegular(this, SymName, IsCOMDAT);
+    }
+    SymbolBodies.push_back(Sym->body());
+  }
+  Directives = Obj->getCOFFLinkerOpts();
+}
+
+MachineTypes BitcodeFile::getMachineType() {
+  switch (Triple(Obj->getTargetTriple()).getArch()) {
+  case Triple::x86_64:
+    return AMD64;
+  case Triple::x86:
+    return I386;
+  case Triple::arm:
+    return ARMNT;
+  case Triple::aarch64:
+    return ARM64;
+  default:
+    return IMAGE_FILE_MACHINE_UNKNOWN;
+  }
+}
+} // namespace coff
+} // namespace lld
+
+// Returns the last element of a path, which is supposed to be a filename.
+static StringRef getBasename(StringRef Path) {
+  size_t Pos = Path.find_last_of("\\/");
+  if (Pos == StringRef::npos)
+    return Path;
+  return Path.substr(Pos + 1);
+}
+
+// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
+std::string lld::toString(coff::InputFile *File) {
+  if (!File)
+    return "(internal)";
+  if (File->ParentName.empty())
+    return File->getName().lower();
+
+  std::string Res =
+      (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")")
+          .str();
+  return StringRef(Res).lower();
+}
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
new file mode 100644 (file)
index 0000000..99868d9
--- /dev/null
@@ -0,0 +1,223 @@
+//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_INPUT_FILES_H
+#define LLD_COFF_INPUT_FILES_H
+
+#include "Config.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/StringSaver.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace llvm {
+namespace pdb {
+class DbiModuleDescriptorBuilder;
+}
+}
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::MachineTypes;
+using llvm::object::Archive;
+using llvm::object::COFFObjectFile;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_import_header;
+using llvm::object::coff_section;
+
+class Chunk;
+class Defined;
+class DefinedImportData;
+class DefinedImportThunk;
+class Lazy;
+class SectionChunk;
+struct Symbol;
+class SymbolBody;
+class Undefined;
+
+// The root class of input files.
+class InputFile {
+public:
+  enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
+  Kind kind() const { return FileKind; }
+  virtual ~InputFile() {}
+
+  // Returns the filename.
+  StringRef getName() { return MB.getBufferIdentifier(); }
+
+  // Reads a file (the constructor doesn't do that).
+  virtual void parse() = 0;
+
+  // Returns the CPU type this file was compiled to.
+  virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
+
+  MemoryBufferRef MB;
+
+  // An archive file name if this file is created from an archive.
+  StringRef ParentName;
+
+  // Returns .drectve section contents if exist.
+  StringRef getDirectives() { return StringRef(Directives).trim(); }
+
+protected:
+  InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+
+  std::string Directives;
+
+private:
+  const Kind FileKind;
+};
+
+// .lib or .a file.
+class ArchiveFile : public InputFile {
+public:
+  explicit ArchiveFile(MemoryBufferRef M);
+  static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+  void parse() override;
+
+  // Enqueues an archive member load for the given symbol. If we've already
+  // enqueued a load for the same archive member, this function does nothing,
+  // which ensures that we don't load the same member more than once.
+  void addMember(const Archive::Symbol *Sym);
+
+private:
+  std::unique_ptr<Archive> File;
+  std::string Filename;
+  llvm::DenseSet<uint64_t> Seen;
+};
+
+// .obj or .o file. This may be a member of an archive file.
+class ObjectFile : public InputFile {
+public:
+  explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
+  void parse() override;
+  MachineTypes getMachineType() override;
+  std::vector<Chunk *> &getChunks() { return Chunks; }
+  std::vector<SectionChunk *> &getDebugChunks() { return DebugChunks; }
+  std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; }
+
+  // Returns a SymbolBody object for the SymbolIndex'th symbol in the
+  // underlying object file.
+  SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
+    return SparseSymbolBodies[SymbolIndex];
+  }
+
+  // Returns the underying COFF file.
+  COFFObjectFile *getCOFFObj() { return COFFObj.get(); }
+
+  // True if this object file is compatible with SEH.
+  // COFF-specific and x86-only.
+  bool SEHCompat = false;
+
+  // The list of safe exception handlers listed in .sxdata section.
+  // COFF-specific and x86-only.
+  std::set<SymbolBody *> SEHandlers;
+
+  // Pointer to the PDB module descriptor builder. Various debug info records
+  // will reference object files by "module index", which is here. Things like
+  // source files and section contributions are also recorded here. Will be null
+  // if we are not producing a PDB.
+  llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr;
+
+private:
+  void initializeChunks();
+  void initializeSymbols();
+  void initializeSEH();
+
+  SymbolBody *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst);
+  SymbolBody *createUndefined(COFFSymbolRef Sym);
+
+  std::unique_ptr<COFFObjectFile> COFFObj;
+  const coff_section *SXData = nullptr;
+
+  // List of all chunks defined by this file. This includes both section
+  // chunks and non-section chunks for common symbols.
+  std::vector<Chunk *> Chunks;
+
+  // CodeView debug info sections.
+  std::vector<SectionChunk *> DebugChunks;
+
+  // This vector contains the same chunks as Chunks, but they are
+  // indexed such that you can get a SectionChunk by section index.
+  // Nonexistent section indices are filled with null pointers.
+  // (Because section number is 1-based, the first slot is always a
+  // null pointer.)
+  std::vector<Chunk *> SparseChunks;
+
+  // List of all symbols referenced or defined by this file.
+  std::vector<SymbolBody *> SymbolBodies;
+
+  // This vector contains the same symbols as SymbolBodies, but they
+  // are indexed such that you can get a SymbolBody by symbol
+  // index. Nonexistent indices (which are occupied by auxiliary
+  // symbols in the real symbol table) are filled with null pointers.
+  std::vector<SymbolBody *> SparseSymbolBodies;
+};
+
+// This type represents import library members that contain DLL names
+// and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7
+// for details about the format.
+class ImportFile : public InputFile {
+public:
+  explicit ImportFile(MemoryBufferRef M)
+      : InputFile(ImportKind, M), Live(!Config->DoGC) {}
+
+  static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
+
+  DefinedImportData *ImpSym = nullptr;
+  DefinedImportData *ConstSym = nullptr;
+  DefinedImportThunk *ThunkSym = nullptr;
+  std::string DLLName;
+
+private:
+  void parse() override;
+
+public:
+  StringRef ExternalName;
+  const coff_import_header *Hdr;
+  Chunk *Location = nullptr;
+
+  // We want to eliminate dllimported symbols if no one actually refers them.
+  // This "Live" bit is used to keep track of which import library members
+  // are actually in use.
+  //
+  // If the Live bit is turned off by MarkLive, Writer will ignore dllimported
+  // symbols provided by this import library member.
+  bool Live;
+};
+
+// Used for LTO.
+class BitcodeFile : public InputFile {
+public:
+  explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+  std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; }
+  MachineTypes getMachineType() override;
+  std::unique_ptr<llvm::lto::InputFile> Obj;
+
+private:
+  void parse() override;
+
+  std::vector<SymbolBody *> SymbolBodies;
+};
+} // namespace coff
+
+std::string toString(coff::InputFile *File);
+} // namespace lld
+
+#endif
diff --git a/COFF/LTO.cpp b/COFF/LTO.cpp
new file mode 100644 (file)
index 0000000..6883b3b
--- /dev/null
@@ -0,0 +1,140 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Core/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+static void diagnosticHandler(const DiagnosticInfo &DI) {
+  SmallString<128> ErrStorage;
+  raw_svector_ostream OS(ErrStorage);
+  DiagnosticPrinterRawOStream DP(OS);
+  DI.print(DP);
+  warn(ErrStorage);
+}
+
+static void checkError(Error E) {
+  handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
+    error(EIB.message());
+    return Error::success();
+  });
+}
+
+static void saveBuffer(StringRef Buffer, const Twine &Path) {
+  std::error_code EC;
+  raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+  if (EC)
+    error("cannot create " + Path + ": " + EC.message());
+  OS << Buffer;
+}
+
+static std::unique_ptr<lto::LTO> createLTO() {
+  lto::Config Conf;
+  Conf.Options = InitTargetOptionsFromCodeGenFlags();
+  Conf.RelocModel = Reloc::PIC_;
+  Conf.DisableVerify = true;
+  Conf.DiagHandler = diagnosticHandler;
+  Conf.OptLevel = Config->LTOOptLevel;
+  if (Config->SaveTemps)
+    checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
+                                 /*UseInputModulePath*/ true));
+  lto::ThinBackend Backend;
+  if (Config->LTOJobs != 0)
+    Backend = lto::createInProcessThinBackend(Config->LTOJobs);
+  return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+                                     Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+  replaceBody<Undefined>(S, S->body()->getName());
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+  lto::InputFile &Obj = *F.Obj;
+  unsigned SymNum = 0;
+  std::vector<SymbolBody *> SymBodies = F.getSymbols();
+  std::vector<lto::SymbolResolution> Resols(SymBodies.size());
+
+  // Provide a resolution to the LTO API for each symbol.
+  for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+    SymbolBody *B = SymBodies[SymNum];
+    Symbol *Sym = B->symbol();
+    lto::SymbolResolution &R = Resols[SymNum];
+    ++SymNum;
+
+    // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+    // reports two symbols for module ASM defined. Without this check, lld
+    // flags an undefined in IR with a definition in ASM as prevailing.
+    // Once IRObjectFile is fixed to report only one symbol this hack can
+    // be removed.
+    R.Prevailing = !ObjSym.isUndefined() && B->getFile() == &F;
+    R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
+    if (R.Prevailing)
+      undefine(Sym);
+  }
+  checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting objects.
+std::vector<StringRef> BitcodeCompiler::compile() {
+  unsigned MaxTasks = LTOObj->getMaxTasks();
+  Buff.resize(MaxTasks);
+
+  checkError(LTOObj->run([&](size_t Task) {
+    return llvm::make_unique<lto::NativeObjectStream>(
+        llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+  }));
+
+  std::vector<StringRef> Ret;
+  for (unsigned I = 0; I != MaxTasks; ++I) {
+    if (Buff[I].empty())
+      continue;
+    if (Config->SaveTemps) {
+      if (I == 0)
+        saveBuffer(Buff[I], Config->OutputFile + ".lto.obj");
+      else
+        saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj");
+    }
+    Ret.emplace_back(Buff[I].data(), Buff[I].size());
+  }
+  return Ret;
+}
diff --git a/COFF/LTO.h b/COFF/LTO.h
new file mode 100644 (file)
index 0000000..194a4cc
--- /dev/null
@@ -0,0 +1,56 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one COFF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular COFF files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// a COFF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_LTO_H
+#define LLD_COFF_LTO_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+}
+
+namespace lld {
+namespace coff {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+  BitcodeCompiler();
+  ~BitcodeCompiler();
+
+  void add(BitcodeFile &F);
+  std::vector<StringRef> compile();
+
+private:
+  std::unique_ptr<llvm::lto::LTO> LTOObj;
+  std::vector<SmallString<0>> Buff;
+};
+}
+}
+
+#endif
diff --git a/COFF/MapFile.cpp b/COFF/MapFile.cpp
new file mode 100644 (file)
index 0000000..b63d467
--- /dev/null
@@ -0,0 +1,125 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the /lldmap option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+//   Address  Size     Align Out     File    Symbol
+//   00201000 00000015     4 .text
+//   00201000 0000000e     4         test.o:(.text)
+//   0020100e 00000000     0                 local
+//   00201005 00000000     0                 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "Error.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>
+    SymbolMapTy;
+
+// Print out the first three columns of a line.
+static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
+                        uint64_t Align) {
+  OS << format("%08llx %08llx %5lld ", Addr, Size, Align);
+}
+
+static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
+
+// Returns a list of all symbols that we want to print out.
+static std::vector<DefinedRegular *> getSymbols() {
+  std::vector<DefinedRegular *> V;
+  for (coff::ObjectFile *File : Symtab->ObjectFiles)
+    for (SymbolBody *B : File->getSymbols())
+      if (auto *Sym = dyn_cast<DefinedRegular>(B))
+        if (Sym && !Sym->getCOFFSymbol().isSectionDefinition())
+          V.push_back(Sym);
+  return V;
+}
+
+// Returns a map from sections to their symbols.
+static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
+  SymbolMapTy Ret;
+  for (DefinedRegular *S : Syms)
+    Ret[S->getChunk()].push_back(S);
+
+  // Sort symbols by address.
+  for (auto &It : Ret) {
+    SmallVectorImpl<DefinedRegular *> &V = It.second;
+    std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
+      return A->getRVA() < B->getRVA();
+    });
+  }
+  return Ret;
+}
+
+// Construct a map from symbols to their stringified representations.
+static DenseMap<DefinedRegular *, std::string>
+getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
+  std::vector<std::string> Str(Syms.size());
+  for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) {
+    raw_string_ostream OS(Str[I]);
+    writeHeader(OS, Syms[I]->getRVA(), 0, 0);
+    OS << indent(2) << toString(*Syms[I]);
+  });
+
+  DenseMap<DefinedRegular *, std::string> Ret;
+  for (size_t I = 0, E = Syms.size(); I < E; ++I)
+    Ret[Syms[I]] = std::move(Str[I]);
+  return Ret;
+}
+
+void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
+  if (Config->MapFile.empty())
+    return;
+
+  std::error_code EC;
+  raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+  if (EC)
+    fatal("cannot open " + Config->MapFile + ": " + EC.message());
+
+  // Collect symbol info that we want to print out.
+  std::vector<DefinedRegular *> Syms = getSymbols();
+  SymbolMapTy SectionSyms = getSectionSyms(Syms);
+  DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings(Syms);
+
+  // Print out the header line.
+  OS << "Address  Size     Align Out     In      Symbol\n";
+
+  // Print out file contents.
+  for (OutputSection *Sec : OutputSections) {
+    writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
+    OS << Sec->getName() << '\n';
+
+    for (Chunk *C : Sec->getChunks()) {
+      auto *SC = dyn_cast<SectionChunk>(C);
+      if (!SC)
+        continue;
+
+      writeHeader(OS, SC->getRVA(), SC->getSize(), SC->getAlign());
+      OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName()
+         << ")\n";
+      for (DefinedRegular *Sym : SectionSyms[SC])
+        OS << SymStr[Sym] << '\n';
+    }
+  }
+}
diff --git a/COFF/MapFile.h b/COFF/MapFile.h
new file mode 100644 (file)
index 0000000..0d0d68c
--- /dev/null
@@ -0,0 +1,22 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MAPFILE_H
+#define LLD_COFF_MAPFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+class OutputSection;
+void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+}
+}
+
+#endif
diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp
new file mode 100644 (file)
index 0000000..a2756e5
--- /dev/null
@@ -0,0 +1,75 @@
+//===- MarkLive.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+// Set live bit on for each reachable chunk. Unmarked (unreachable)
+// COMDAT chunks will be ignored by Writer, so they will be excluded
+// from the final output.
+void markLive(const std::vector<Chunk *> &Chunks) {
+  // We build up a worklist of sections which have been marked as live. We only
+  // push into the worklist when we discover an unmarked section, and we mark
+  // as we push, so sections never appear twice in the list.
+  SmallVector<SectionChunk *, 256> Worklist;
+
+  // COMDAT section chunks are dead by default. Add non-COMDAT chunks.
+  for (Chunk *C : Chunks)
+    if (auto *SC = dyn_cast<SectionChunk>(C))
+      if (SC->isLive())
+        Worklist.push_back(SC);
+
+  auto Enqueue = [&](SectionChunk *C) {
+    if (C->isLive())
+      return;
+    C->markLive();
+    Worklist.push_back(C);
+  };
+
+  auto AddSym = [&](SymbolBody *B) {
+    if (auto *Sym = dyn_cast<DefinedRegular>(B))
+      Enqueue(Sym->getChunk());
+    else if (auto *Sym = dyn_cast<DefinedImportData>(B))
+      Sym->File->Live = true;
+    else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
+      Sym->WrappedSym->File->Live = true;
+  };
+
+  // Add GC root chunks.
+  for (SymbolBody *B : Config->GCRoot)
+    AddSym(B);
+
+  while (!Worklist.empty()) {
+    SectionChunk *SC = Worklist.pop_back_val();
+
+    // If this section was discarded, there are relocations referring to
+    // discarded sections. Ignore these sections to avoid crashing. They will be
+    // diagnosed during relocation processing.
+    if (SC->isDiscarded())
+      continue;
+
+    assert(SC->isLive() && "We mark as live when pushing onto the worklist!");
+
+    // Mark all symbols listed in the relocation table for this section.
+    for (SymbolBody *B : SC->symbols())
+      AddSym(B);
+
+    // Mark associative sections if any.
+    for (SectionChunk *C : SC->children())
+      Enqueue(C);
+  }
+}
+
+}
+}
diff --git a/COFF/Memory.h b/COFF/Memory.h
new file mode 100644 (file)
index 0000000..526f113
--- /dev/null
@@ -0,0 +1,52 @@
+//===- Memory.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// See ELF/Memory.h
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MEMORY_H
+#define LLD_COFF_MEMORY_H
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/StringSaver.h"
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+extern llvm::BumpPtrAllocator BAlloc;
+extern llvm::StringSaver Saver;
+
+struct SpecificAllocBase {
+  SpecificAllocBase() { Instances.push_back(this); }
+  virtual ~SpecificAllocBase() = default;
+  virtual void reset() = 0;
+  static std::vector<SpecificAllocBase *> Instances;
+};
+
+template <class T> struct SpecificAlloc : public SpecificAllocBase {
+  void reset() override { Alloc.DestroyAll(); }
+  llvm::SpecificBumpPtrAllocator<T> Alloc;
+};
+
+template <typename T, typename... U> T *make(U &&... Args) {
+  static SpecificAlloc<T> Alloc;
+  return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
+}
+
+inline void freeArena() {
+  for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
+    Alloc->reset();
+  BAlloc.Reset();
+}
+}
+}
+
+#endif
diff --git a/COFF/Options.td b/COFF/Options.td
new file mode 100644 (file)
index 0000000..61523c4
--- /dev/null
@@ -0,0 +1,139 @@
+include "llvm/Option/OptParser.td"
+
+// link.exe accepts options starting with either a dash or a slash.
+
+// Flag that takes no arguments.
+class F<string name> : Flag<["/", "-", "-?"], name>;
+
+// Flag that takes one argument after ":".
+class P<string name, string help> :
+      Joined<["/", "-", "-?"], name#":">, HelpText<help>;
+
+// Boolean flag suffixed by ":no".
+multiclass B<string name, string help> {
+  def "" : F<name>;
+  def _no : F<name#":no">, HelpText<help>;
+}
+
+def align   : P<"align", "Section alignment">;
+def alternatename : P<"alternatename", "Define weak alias">;
+def base    : P<"base", "Base address of the program">;
+def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
+def delayload : P<"delayload", "Delay loaded DLL name">;
+def entry   : P<"entry", "Name of entry point symbol">;
+def errorlimit : P<"errorlimit",
+    "Maximum number of errors to emit before stopping (0 = no limit)">;
+def export  : P<"export", "Export a function">;
+// No help text because /failifmismatch is not intended to be used by the user.
+def failifmismatch : P<"failifmismatch", "">;
+def heap    : P<"heap", "Size of the heap">;
+def implib  : P<"implib", "Import library name">;
+def libpath : P<"libpath", "Additional library search path">;
+def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
+def lldsavetemps : F<"lldsavetemps">,
+    HelpText<"Save temporary files instead of deleting them">;
+def machine : P<"machine", "Specify target platform">;
+def merge   : P<"merge", "Combine sections">;
+def mllvm   : P<"mllvm", "Options to pass to LLVM">;
+def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
+def opt     : P<"opt", "Control optimizations">;
+def out     : P<"out", "Path to file to write output">;
+def pdb : P<"pdb", "PDB file path">;
+def section : P<"section", "Specify section attributes">;
+def stack   : P<"stack", "Size of the stack">;
+def stub    : P<"stub", "Specify DOS stub file">;
+def subsystem : P<"subsystem", "Specify subsystem">;
+def version : P<"version", "Specify a version number in the PE header">;
+
+def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
+
+def manifest : F<"manifest">;
+def manifest_colon : P<"manifest", "Create manifest file">;
+def manifestuac : P<"manifestuac", "User access control">;
+def manifestfile : P<"manifestfile", "Manifest file path">;
+def manifestdependency : P<"manifestdependency",
+                           "Attributes for <dependency> in manifest file">;
+def manifestinput : P<"manifestinput", "Specify manifest file">;
+
+// We cannot use multiclass P because class name "incl" is different
+// from its command line option name. We do this because "include" is
+// a reserved keyword in tablegen.
+def incl : Joined<["/", "-"], "include:">,
+    HelpText<"Force symbol to be added to symbol table as undefined one">;
+
+// "def" is also a keyword.
+def deffile : Joined<["/", "-"], "def:">,
+    HelpText<"Use module-definition file">;
+
+def debug : F<"debug">, HelpText<"Embed a symbol table in the image">;
+def debugtype : P<"debugtype", "Debug Info Options">;
+def dll : F<"dll">, HelpText<"Create a DLL">;
+def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">;
+def nodefaultlib_all : F<"nodefaultlib">;
+def noentry : F<"noentry">;
+def profile : F<"profile">;
+def swaprun_cd : F<"swaprun:cd">;
+def swaprun_net : F<"swaprun:net">;
+def verbose : F<"verbose">;
+
+def force : F<"force">,
+    HelpText<"Allow undefined symbols when creating executables">;
+def force_unresolved : F<"force:unresolved">;
+
+defm allowbind: B<"allowbind", "Disable DLL binding">;
+defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
+defm appcontainer : B<"appcontainer",
+                      "Image can only be run in an app container">;
+defm dynamicbase : B<"dynamicbase",
+                     "Disable address space layout randomization">;
+defm fixed    : B<"fixed", "Enable base relocations">;
+defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">;
+defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">;
+defm nxcompat : B<"nxcompat", "Disable data execution provention">;
+defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">;
+defm tsaware  : B<"tsaware", "Create non-Terminal Server aware executable">;
+
+def help : F<"help">;
+def help_q : Flag<["/?", "-?"], "">, Alias<help>;
+
+// LLD extensions
+def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">;
+def nosymtab : F<"nosymtab">;
+def msvclto : F<"msvclto">;
+
+// Flags for debugging
+def lldmap : F<"lldmap">;
+def lldmap_file : Joined<["/", "-"], "lldmap:">;
+
+//==============================================================================
+// The flags below do nothing. They are defined only for link.exe compatibility.
+//==============================================================================
+
+class QF<string name> : Joined<["/", "-", "-?"], name#":">;
+
+multiclass QB<string name> {
+  def "" : F<name>;
+  def _no : F<name#":no">;
+}
+
+def functionpadmin : F<"functionpadmin">;
+def ignoreidl : F<"ignoreidl">;
+def incremental : F<"incremental">;
+def no_incremental : F<"incremental:no">;
+def nologo : F<"nologo">;
+def throwingnew : F<"throwingnew">;
+def editandcontinue : F<"editandcontinue">;
+def fastfail : F<"fastfail">;
+
+def delay : QF<"delay">;
+def errorreport : QF<"errorreport">;
+def idlout : QF<"idlout">;
+def ignore : QF<"ignore">;
+def maxilksize : QF<"maxilksize">;
+def pdbaltpath : QF<"pdbaltpath">;
+def tlbid : QF<"tlbid">;
+def tlbout : QF<"tlbout">;
+def verbose_all : QF<"verbose">;
+def guardsym : QF<"guardsym">;
+
+defm wx : QB<"wx">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
new file mode 100644 (file)
index 0000000..89462da
--- /dev/null
@@ -0,0 +1,672 @@
+//===- PDB.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PDB.h"
+#include "Chunks.h"
+#include "Config.h"
+#include "Error.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <memory>
+
+using namespace lld;
+using namespace lld::coff;
+using namespace llvm;
+using namespace llvm::codeview;
+
+using llvm::object::coff_section;
+
+static ExitOnError ExitOnErr;
+
+namespace {
+/// Map from type index and item index in a type server PDB to the
+/// corresponding index in the destination PDB.
+struct CVIndexMap {
+  SmallVector<TypeIndex, 0> TPIMap;
+  SmallVector<TypeIndex, 0> IPIMap;
+  bool IsTypeServerMap = false;
+};
+
+class PDBLinker {
+public:
+  PDBLinker(SymbolTable *Symtab)
+      : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc),
+        IDTable(Alloc) {}
+
+  /// Emit the basic PDB structure: initial streams, headers, etc.
+  void initialize(const llvm::codeview::DebugInfo *DI);
+
+  /// Link CodeView from each object file in the symbol table into the PDB.
+  void addObjectsToPDB();
+
+  /// Link CodeView from a single object file into the PDB.
+  void addObjectFile(ObjectFile *File);
+
+  /// Produce a mapping from the type and item indices used in the object
+  /// file to those in the destination PDB.
+  ///
+  /// If the object file uses a type server PDB (compiled with /Zi), merge TPI
+  /// and IPI from the type server PDB and return a map for it. Each unique type
+  /// server PDB is merged at most once, so this may return an existing index
+  /// mapping.
+  ///
+  /// If the object does not use a type server PDB (compiled with /Z7), we merge
+  /// all the type and item records from the .debug$S stream and fill in the
+  /// caller-provided ObjectIndexMap.
+  const CVIndexMap &mergeDebugT(ObjectFile *File, CVIndexMap &ObjectIndexMap);
+
+  const CVIndexMap &maybeMergeTypeServerPDB(ObjectFile *File,
+                                            TypeServer2Record &TS);
+
+  /// Add the section map and section contributions to the PDB.
+  void addSections(ArrayRef<uint8_t> SectionTable);
+
+  /// Write the PDB to disk.
+  void commit();
+
+private:
+  BumpPtrAllocator Alloc;
+
+  SymbolTable *Symtab;
+
+  pdb::PDBFileBuilder Builder;
+
+  /// Type records that will go into the PDB TPI stream.
+  TypeTableBuilder TypeTable;
+
+  /// Item records that will go into the PDB IPI stream.
+  TypeTableBuilder IDTable;
+
+  /// PDBs use a single global string table for filenames in the file checksum
+  /// table.
+  DebugStringTableSubsection PDBStrTab;
+
+  llvm::SmallString<128> NativePath;
+
+  std::vector<pdb::SecMapEntry> SectionMap;
+
+  /// Type index mappings of type server PDBs that we've loaded so far.
+  std::map<GUID, CVIndexMap> TypeServerIndexMappings;
+};
+}
+
+// Returns a list of all SectionChunks.
+static void addSectionContribs(SymbolTable *Symtab,
+                               pdb::DbiStreamBuilder &DbiBuilder) {
+  for (Chunk *C : Symtab->getChunks())
+    if (auto *SC = dyn_cast<SectionChunk>(C))
+      DbiBuilder.addSectionContrib(SC->File->ModuleDBI, SC->Header);
+}
+
+static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
+                                StringRef Name) {
+  for (SectionChunk *C : Sections)
+    if (C->getSectionName() == Name)
+      return C;
+  return nullptr;
+}
+
+static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
+                                           StringRef SecName) {
+  // First 4 bytes are section magic.
+  if (Data.size() < 4)
+    fatal(SecName + " too short");
+  if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
+    fatal(SecName + " has an invalid magic");
+  return Data.slice(4);
+}
+
+static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
+  if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName))
+    return consumeDebugMagic(Sec->getContents(), SecName);
+  return {};
+}
+
+static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
+                        TypeTableBuilder &TypeTable) {
+  // Start the TPI or IPI stream header.
+  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+
+  // Flatten the in memory type table.
+  TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
+    // FIXME: Hash types.
+    TpiBuilder.addTypeRecord(Rec, None);
+  });
+}
+
+static Optional<TypeServer2Record>
+maybeReadTypeServerRecord(CVTypeArray &Types) {
+  auto I = Types.begin();
+  if (I == Types.end())
+    return None;
+  const CVType &Type = *I;
+  if (Type.kind() != LF_TYPESERVER2)
+    return None;
+  TypeServer2Record TS;
+  if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), TS))
+    fatal(EC, "error reading type server record");
+  return std::move(TS);
+}
+
+const CVIndexMap &PDBLinker::mergeDebugT(ObjectFile *File,
+                                         CVIndexMap &ObjectIndexMap) {
+  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
+  if (Data.empty())
+    return ObjectIndexMap;
+
+  BinaryByteStream Stream(Data, support::little);
+  CVTypeArray Types;
+  BinaryStreamReader Reader(Stream);
+  if (auto EC = Reader.readArray(Types, Reader.getLength()))
+    fatal(EC, "Reader::readArray failed");
+
+  // Look through type servers. If we've already seen this type server, don't
+  // merge any type information.
+  if (Optional<TypeServer2Record> TS = maybeReadTypeServerRecord(Types))
+    return maybeMergeTypeServerPDB(File, *TS);
+
+  // This is a /Z7 object. Fill in the temporary, caller-provided
+  // ObjectIndexMap.
+  if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable,
+                                       ObjectIndexMap.TPIMap, Types))
+    fatal(Err, "codeview::mergeTypeAndIdRecords failed");
+  return ObjectIndexMap;
+}
+
+static Expected<std::unique_ptr<pdb::NativeSession>>
+tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) {
+  std::unique_ptr<pdb::IPDBSession> ThisSession;
+  if (auto EC =
+          pdb::loadDataForPDB(pdb::PDB_ReaderType::Native, TSPath, ThisSession))
+    return std::move(EC);
+
+  std::unique_ptr<pdb::NativeSession> NS(
+      static_cast<pdb::NativeSession *>(ThisSession.release()));
+  pdb::PDBFile &File = NS->getPDBFile();
+  auto ExpectedInfo = File.getPDBInfoStream();
+  // All PDB Files should have an Info stream.
+  if (!ExpectedInfo)
+    return ExpectedInfo.takeError();
+
+  // Just because a file with a matching name was found and it was an actual
+  // PDB file doesn't mean it matches.  For it to match the InfoStream's GUID
+  // must match the GUID specified in the TypeServer2 record.
+  if (ExpectedInfo->getGuid() != GuidFromObj)
+    return make_error<pdb::GenericError>(
+        pdb::generic_error_code::type_server_not_found, TSPath);
+
+  return std::move(NS);
+}
+
+const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjectFile *File,
+                                                     TypeServer2Record &TS) {
+  // First, check if we already loaded a PDB with this GUID. Return the type
+  // index mapping if we have it.
+  auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()});
+  CVIndexMap &IndexMap = Insertion.first->second;
+  if (!Insertion.second)
+    return IndexMap;
+
+  // Mark this map as a type server map.
+  IndexMap.IsTypeServerMap = true;
+
+  // Check for a PDB at:
+  // 1. The given file path
+  // 2. Next to the object file or archive file
+  auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName());
+  if (!ExpectedSession) {
+    consumeError(ExpectedSession.takeError());
+    StringRef LocalPath =
+        !File->ParentName.empty() ? File->ParentName : File->getName();
+    SmallString<128> Path = sys::path::parent_path(LocalPath);
+    sys::path::append(
+        Path, sys::path::filename(TS.getName(), sys::path::Style::windows));
+    ExpectedSession = tryToLoadPDB(TS.getGuid(), Path);
+  }
+  if (auto E = ExpectedSession.takeError())
+    fatal(E, "Type server PDB was not found");
+
+  // Merge TPI first, because the IPI stream will reference type indices.
+  auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream();
+  if (auto E = ExpectedTpi.takeError())
+    fatal(E, "Type server does not have TPI stream");
+  if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap,
+                                  ExpectedTpi->typeArray()))
+    fatal(Err, "codeview::mergeTypeRecords failed");
+
+  // Merge IPI.
+  auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream();
+  if (auto E = ExpectedIpi.takeError())
+    fatal(E, "Type server does not have TPI stream");
+  if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap,
+                                ExpectedIpi->typeArray()))
+    fatal(Err, "codeview::mergeIdRecords failed");
+
+  return IndexMap;
+}
+
+static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
+  if (TI.isSimple())
+    return true;
+  if (TI.toArrayIndex() >= TypeIndexMap.size())
+    return false;
+  TI = TypeIndexMap[TI.toArrayIndex()];
+  return true;
+}
+
+static void remapTypesInSymbolRecord(ObjectFile *File,
+                                     MutableArrayRef<uint8_t> Contents,
+                                     const CVIndexMap &IndexMap,
+                                     ArrayRef<TiReference> TypeRefs) {
+  for (const TiReference &Ref : TypeRefs) {
+    unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
+    if (Contents.size() < Ref.Offset + ByteSize)
+      fatal("symbol record too short");
+
+    // This can be an item index or a type index. Choose the appropriate map.
+    ArrayRef<TypeIndex> TypeOrItemMap = IndexMap.TPIMap;
+    if (Ref.Kind == TiRefKind::IndexRef && IndexMap.IsTypeServerMap)
+      TypeOrItemMap = IndexMap.IPIMap;
+
+    MutableArrayRef<TypeIndex> TIs(
+        reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count);
+    for (TypeIndex &TI : TIs) {
+      if (!remapTypeIndex(TI, TypeOrItemMap)) {
+        TI = TypeIndex(SimpleTypeKind::NotTranslated);
+        log("ignoring symbol record in " + File->getName() +
+            " with bad type index 0x" + utohexstr(TI.getIndex()));
+        continue;
+      }
+    }
+  }
+}
+
+/// MSVC translates S_PROC_ID_END to S_END.
+uint16_t canonicalizeSymbolKind(SymbolKind Kind) {
+  if (Kind == SymbolKind::S_PROC_ID_END)
+    return SymbolKind::S_END;
+  return Kind;
+}
+
+/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned.
+/// The object file may not be aligned.
+static MutableArrayRef<uint8_t> copySymbolForPdb(const CVSymbol &Sym,
+                                                 BumpPtrAllocator &Alloc) {
+  size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
+  assert(Size >= 4 && "record too short");
+  assert(Size <= MaxRecordLength && "record too long");
+  void *Mem = Alloc.Allocate(Size, 4);
+
+  // Copy the symbol record and zero out any padding bytes.
+  MutableArrayRef<uint8_t> NewData(reinterpret_cast<uint8_t *>(Mem), Size);
+  memcpy(NewData.data(), Sym.data().data(), Sym.length());
+  memset(NewData.data() + Sym.length(), 0, Size - Sym.length());
+
+  // Update the record prefix length. It should point to the beginning of the
+  // next record. MSVC does some canonicalization of the record kind, so we do
+  // that as well.
+  auto *Prefix = reinterpret_cast<RecordPrefix *>(Mem);
+  Prefix->RecordKind = canonicalizeSymbolKind(Sym.kind());
+  Prefix->RecordLen = Size - 2;
+  return NewData;
+}
+
+/// Return true if this symbol opens a scope. This implies that the symbol has
+/// "parent" and "end" fields, which contain the offset of the S_END or
+/// S_INLINESITE_END record.
+static bool symbolOpensScope(SymbolKind Kind) {
+  switch (Kind) {
+  case SymbolKind::S_GPROC32:
+  case SymbolKind::S_LPROC32:
+  case SymbolKind::S_LPROC32_ID:
+  case SymbolKind::S_GPROC32_ID:
+  case SymbolKind::S_BLOCK32:
+  case SymbolKind::S_SEPCODE:
+  case SymbolKind::S_THUNK32:
+  case SymbolKind::S_INLINESITE:
+  case SymbolKind::S_INLINESITE2:
+    return true;
+  default:
+    break;
+  }
+  return false;
+}
+
+static bool symbolEndsScope(SymbolKind Kind) {
+  switch (Kind) {
+  case SymbolKind::S_END:
+  case SymbolKind::S_PROC_ID_END:
+  case SymbolKind::S_INLINESITE_END:
+    return true;
+  default:
+    break;
+  }
+  return false;
+}
+
+struct ScopeRecord {
+  ulittle32_t PtrParent;
+  ulittle32_t PtrEnd;
+};
+
+struct SymbolScope {
+  ScopeRecord *OpeningRecord;
+  uint32_t ScopeOffset;
+};
+
+static void scopeStackOpen(SmallVectorImpl<SymbolScope> &Stack,
+                           uint32_t CurOffset, CVSymbol &Sym) {
+  assert(symbolOpensScope(Sym.kind()));
+  SymbolScope S;
+  S.ScopeOffset = CurOffset;
+  S.OpeningRecord = const_cast<ScopeRecord *>(
+      reinterpret_cast<const ScopeRecord *>(Sym.content().data()));
+  S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset;
+  Stack.push_back(S);
+}
+
+static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
+                            uint32_t CurOffset, ObjectFile *File) {
+  if (Stack.empty()) {
+    warn("symbol scopes are not balanced in " + File->getName());
+    return;
+  }
+  SymbolScope S = Stack.pop_back_val();
+  S.OpeningRecord->PtrEnd = CurOffset;
+}
+
+static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
+                               const CVIndexMap &IndexMap,
+                               BinaryStreamRef SymData) {
+  // FIXME: Improve error recovery by warning and skipping records when
+  // possible.
+  CVSymbolArray Syms;
+  BinaryStreamReader Reader(SymData);
+  ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
+  SmallVector<SymbolScope, 4> Scopes;
+  for (const CVSymbol &Sym : Syms) {
+    // Discover type index references in the record. Skip it if we don't know
+    // where they are.
+    SmallVector<TiReference, 32> TypeRefs;
+    if (!discoverTypeIndices(Sym, TypeRefs)) {
+      log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind()));
+      continue;
+    }
+
+    // Copy the symbol record so we can mutate it.
+    MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
+
+    // Re-map all the type index references.
+    MutableArrayRef<uint8_t> Contents =
+        NewData.drop_front(sizeof(RecordPrefix));
+    remapTypesInSymbolRecord(File, Contents, IndexMap, TypeRefs);
+
+    // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+    CVSymbol NewSym(Sym.kind(), NewData);
+    if (symbolOpensScope(Sym.kind()))
+      scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
+    else if (symbolEndsScope(Sym.kind()))
+      scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
+
+    // Add the symbol to the module.
+    File->ModuleDBI->addSymbol(NewSym);
+  }
+}
+
+// Allocate memory for a .debug$S section and relocate it.
+static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc,
+                                            SectionChunk *DebugChunk) {
+  uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk->getSize());
+  assert(DebugChunk->OutputSectionOff == 0 &&
+         "debug sections should not be in output sections");
+  DebugChunk->writeTo(Buffer);
+  return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()),
+                           ".debug$S");
+}
+
+void PDBLinker::addObjectFile(ObjectFile *File) {
+  // Add a module descriptor for every object file. We need to put an absolute
+  // path to the object into the PDB. If this is a plain object, we make its
+  // path absolute. If it's an object in an archive, we make the archive path
+  // absolute.
+  bool InArchive = !File->ParentName.empty();
+  SmallString<128> Path = InArchive ? File->ParentName : File->getName();
+  sys::fs::make_absolute(Path);
+  sys::path::native(Path, sys::path::Style::windows);
+  StringRef Name = InArchive ? File->getName() : StringRef(Path);
+
+  File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
+  File->ModuleDBI->setObjFileName(Path);
+
+  // Before we can process symbol substreams from .debug$S, we need to process
+  // type information, file checksums, and the string table.  Add type info to
+  // the PDB first, so that we can get the map from object file type and item
+  // indices to PDB type and item indices.
+  CVIndexMap ObjectIndexMap;
+  const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap);
+
+  // Now do all live .debug$S sections.
+  for (SectionChunk *DebugChunk : File->getDebugChunks()) {
+    if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
+      continue;
+
+    ArrayRef<uint8_t> RelocatedDebugContents =
+        relocateDebugChunk(Alloc, DebugChunk);
+    if (RelocatedDebugContents.empty())
+      continue;
+
+    DebugSubsectionArray Subsections;
+    BinaryStreamReader Reader(RelocatedDebugContents, support::little);
+    ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
+
+    DebugStringTableSubsectionRef CVStrTab;
+    DebugChecksumsSubsectionRef Checksums;
+    for (const DebugSubsectionRecord &SS : Subsections) {
+      switch (SS.kind()) {
+      case DebugSubsectionKind::StringTable:
+        ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+        break;
+      case DebugSubsectionKind::FileChecksums:
+        ExitOnErr(Checksums.initialize(SS.getRecordData()));
+        break;
+      case DebugSubsectionKind::Lines:
+        // We can add the relocated line table directly to the PDB without
+        // modification because the file checksum offsets will stay the same.
+        File->ModuleDBI->addDebugSubsection(SS);
+        break;
+      case DebugSubsectionKind::Symbols:
+        mergeSymbolRecords(Alloc, File, IndexMap, SS.getRecordData());
+        break;
+      default:
+        // FIXME: Process the rest of the subsections.
+        break;
+      }
+    }
+
+    if (Checksums.valid()) {
+      // Make a new file checksum table that refers to offsets in the PDB-wide
+      // string table. Generally the string table subsection appears after the
+      // checksum table, so we have to do this after looping over all the
+      // subsections.
+      if (!CVStrTab.valid())
+        fatal(".debug$S sections must have both a string table subsection "
+              "and a checksum subsection table or neither");
+      auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab);
+      for (FileChecksumEntry &FC : Checksums) {
+        StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
+        ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI,
+                                                              FileName));
+        NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
+      }
+      File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+    }
+  }
+}
+
+// Add all object files to the PDB. Merge .debug$T sections into IpiData and
+// TpiData.
+void PDBLinker::addObjectsToPDB() {
+  for (ObjectFile *File : Symtab->ObjectFiles)
+    addObjectFile(File);
+
+  Builder.getStringTableBuilder().setStrings(PDBStrTab);
+
+  // Construct TPI stream contents.
+  addTypeInfo(Builder.getTpiBuilder(), TypeTable);
+
+  // Construct IPI stream contents.
+  addTypeInfo(Builder.getIpiBuilder(), IDTable);
+
+  // Add public and symbol records stream.
+
+  // For now we don't actually write any thing useful to the publics stream, but
+  // the act of "getting" it also creates it lazily so that we write an empty
+  // stream.
+  (void)Builder.getPublicsBuilder();
+}
+
+static void addLinkerModuleSymbols(StringRef Path,
+                                   pdb::DbiModuleDescriptorBuilder &Mod,
+                                   BumpPtrAllocator &Allocator) {
+  codeview::SymbolSerializer Serializer(Allocator, CodeViewContainer::Pdb);
+  codeview::ObjNameSym ONS(SymbolRecordKind::ObjNameSym);
+  codeview::Compile3Sym CS(SymbolRecordKind::Compile3Sym);
+  codeview::EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym);
+
+  ONS.Name = "* Linker *";
+  ONS.Signature = 0;
+
+  CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386;
+  CS.Flags = CompileSym3Flags::None;
+  CS.VersionBackendBuild = 0;
+  CS.VersionBackendMajor = 0;
+  CS.VersionBackendMinor = 0;
+  CS.VersionBackendQFE = 0;
+  CS.VersionFrontendBuild = 0;
+  CS.VersionFrontendMajor = 0;
+  CS.VersionFrontendMinor = 0;
+  CS.VersionFrontendQFE = 0;
+  CS.Version = "LLVM Linker";
+  CS.setLanguage(SourceLanguage::Link);
+
+  ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front();
+  std::string ArgStr = llvm::join(Args, " ");
+  EBS.Fields.push_back("cwd");
+  SmallString<64> cwd;
+  sys::fs::current_path(cwd);
+  EBS.Fields.push_back(cwd);
+  EBS.Fields.push_back("exe");
+  EBS.Fields.push_back(Config->Argv[0]);
+  EBS.Fields.push_back("pdb");
+  EBS.Fields.push_back(Path);
+  EBS.Fields.push_back("cmd");
+  EBS.Fields.push_back(ArgStr);
+  Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+      ONS, Allocator, CodeViewContainer::Pdb));
+  Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+      CS, Allocator, CodeViewContainer::Pdb));
+  Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+      EBS, Allocator, CodeViewContainer::Pdb));
+}
+
+// Creates a PDB file.
+void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable,
+                     const llvm::codeview::DebugInfo *DI) {
+  PDBLinker PDB(Symtab);
+  PDB.initialize(DI);
+  PDB.addObjectsToPDB();
+  PDB.addSections(SectionTable);
+  PDB.commit();
+}
+
+void PDBLinker::initialize(const llvm::codeview::DebugInfo *DI) {
+  ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize
+
+  // Create streams in MSF for predefined streams, namely
+  // PDB, TPI, DBI and IPI.
+  for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
+    ExitOnErr(Builder.getMsfBuilder().addStream(0));
+
+  // Add an Info stream.
+  auto &InfoBuilder = Builder.getInfoBuilder();
+  InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);
+
+  GUID uuid{};
+  if (DI)
+    memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
+  InfoBuilder.setGuid(uuid);
+  InfoBuilder.setSignature(time(nullptr));
+  InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
+
+  // Add an empty DBI stream.
+  pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+  DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
+  ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {}));
+}
+
+void PDBLinker::addSections(ArrayRef<uint8_t> SectionTable) {
+  // Add Section Contributions.
+  pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+  addSectionContribs(Symtab, DbiBuilder);
+
+  // Add Section Map stream.
+  ArrayRef<object::coff_section> Sections = {
+      (const object::coff_section *)SectionTable.data(),
+      SectionTable.size() / sizeof(object::coff_section)};
+  SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections);
+  DbiBuilder.setSectionMap(SectionMap);
+
+  // It's not entirely clear what this is, but the * Linker * module uses it.
+  NativePath = Config->PDBPath;
+  sys::fs::make_absolute(NativePath);
+  sys::path::native(NativePath, sys::path::Style::windows);
+  uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
+  auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
+  LinkerModule.setPdbFilePathNI(PdbFilePathNI);
+  addLinkerModuleSymbols(NativePath, LinkerModule, Alloc);
+
+  // Add COFF section header stream.
+  ExitOnErr(
+      DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
+}
+
+void PDBLinker::commit() {
+  // Write to a file.
+  ExitOnErr(Builder.commit(Config->PDBPath));
+}
diff --git a/COFF/PDB.h b/COFF/PDB.h
new file mode 100644 (file)
index 0000000..9aaa317
--- /dev/null
@@ -0,0 +1,31 @@
+//===- PDB.h ----------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_PDB_H
+#define LLD_COFF_PDB_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+namespace codeview {
+union DebugInfo;
+}
+}
+
+namespace lld {
+namespace coff {
+class SymbolTable;
+
+void createPDB(SymbolTable *Symtab, llvm::ArrayRef<uint8_t> SectionTable,
+               const llvm::codeview::DebugInfo *DI);
+}
+}
+
+#endif
diff --git a/COFF/README.md b/COFF/README.md
new file mode 100644 (file)
index 0000000..f1bfc9c
--- /dev/null
@@ -0,0 +1 @@
+See docs/NewLLD.rst
diff --git a/COFF/Strings.cpp b/COFF/Strings.cpp
new file mode 100644 (file)
index 0000000..84f9b9a
--- /dev/null
@@ -0,0 +1,35 @@
+//===- Strings.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Strings.h"
+#include <mutex>
+
+#if defined(_MSC_VER)
+#include <Windows.h>
+#include <DbgHelp.h>
+#pragma comment(lib, "dbghelp.lib")
+#endif
+
+using namespace lld;
+using namespace lld::coff;
+using namespace llvm;
+
+Optional<std::string> coff::demangle(StringRef S) {
+#if defined(_MSC_VER)
+  // UnDecorateSymbolName is not thread-safe, so we need a mutex.
+  static std::mutex Mu;
+  std::lock_guard<std::mutex> Lock(Mu);
+
+  char Buf[4096];
+  if (S.startswith("?"))
+    if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0))
+      return std::string(Buf, Len);
+#endif
+  return None;
+}
diff --git a/COFF/Strings.h b/COFF/Strings.h
new file mode 100644 (file)
index 0000000..1f85f3e
--- /dev/null
@@ -0,0 +1,23 @@
+//===- Strings.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_STRINGS_H
+#define LLD_COFF_STRINGS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace lld {
+namespace coff {
+llvm::Optional<std::string> demangle(llvm::StringRef S);
+}
+}
+
+#endif
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
new file mode 100644 (file)
index 0000000..c06e42b
--- /dev/null
@@ -0,0 +1,375 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolTable.h"
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "LTO.h"
+#include "Memory.h"
+#include "Symbols.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+enum SymbolPreference {
+  SP_EXISTING = -1,
+  SP_CONFLICT = 0,
+  SP_NEW = 1,
+};
+
+/// Checks if an existing symbol S should be kept or replaced by a new symbol.
+/// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol
+/// should be kept, and SP_CONFLICT if no valid resolution exists.
+static SymbolPreference compareDefined(Symbol *S, bool WasInserted,
+                                       bool NewIsCOMDAT) {
+  // If the symbol wasn't previously known, the new symbol wins by default.
+  if (WasInserted || !isa<Defined>(S->body()))
+    return SP_NEW;
+
+  // If the existing symbol is a DefinedRegular, both it and the new symbol
+  // must be comdats. In that case, we have no reason to prefer one symbol
+  // over the other, and we keep the existing one. If one of the symbols
+  // is not a comdat, we report a conflict.
+  if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
+    if (NewIsCOMDAT && R->isCOMDAT())
+      return SP_EXISTING;
+    else
+      return SP_CONFLICT;
+  }
+
+  // Existing symbol is not a DefinedRegular; new symbol wins.
+  return SP_NEW;
+}
+
+SymbolTable *Symtab;
+
+void SymbolTable::addFile(InputFile *File) {
+  log("Reading " + toString(File));
+  File->parse();
+
+  MachineTypes MT = File->getMachineType();
+  if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+    Config->Machine = MT;
+  } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) {
+    fatal(toString(File) + ": machine type " + machineToStr(MT) +
+          " conflicts with " + machineToStr(Config->Machine));
+  }
+
+  if (auto *F = dyn_cast<ObjectFile>(File)) {
+    ObjectFiles.push_back(F);
+  } else if (auto *F = dyn_cast<BitcodeFile>(File)) {
+    BitcodeFiles.push_back(F);
+  } else if (auto *F = dyn_cast<ImportFile>(File)) {
+    ImportFiles.push_back(F);
+  }
+
+  StringRef S = File->getDirectives();
+  if (S.empty())
+    return;
+
+  log("Directives: " + toString(File) + ": " + S);
+  Driver->parseDirectives(S);
+}
+
+void SymbolTable::reportRemainingUndefines() {
+  SmallPtrSet<SymbolBody *, 8> Undefs;
+  for (auto &I : Symtab) {
+    Symbol *Sym = I.second;
+    auto *Undef = dyn_cast<Undefined>(Sym->body());
+    if (!Undef)
+      continue;
+    if (!Sym->IsUsedInRegularObj)
+      continue;
+    StringRef Name = Undef->getName();
+    // A weak alias may have been resolved, so check for that.
+    if (Defined *D = Undef->getWeakAlias()) {
+      // We resolve weak aliases by replacing the alias's SymbolBody with the
+      // target's SymbolBody. This causes all SymbolBody pointers referring to
+      // the old symbol to instead refer to the new symbol. However, we can't
+      // just blindly copy sizeof(Symbol::Body) bytes from D to Sym->Body
+      // because D may be an internal symbol, and internal symbols are stored as
+      // "unparented" SymbolBodies. For that reason we need to check which type
+      // of symbol we are dealing with and copy the correct number of bytes.
+      if (isa<DefinedRegular>(D))
+        memcpy(Sym->Body.buffer, D, sizeof(DefinedRegular));
+      else if (isa<DefinedAbsolute>(D))
+        memcpy(Sym->Body.buffer, D, sizeof(DefinedAbsolute));
+      else
+        // No other internal symbols are possible.
+        Sym->Body = D->symbol()->Body;
+      continue;
+    }
+    // If we can resolve a symbol by removing __imp_ prefix, do that.
+    // This odd rule is for compatibility with MSVC linker.
+    if (Name.startswith("__imp_")) {
+      Symbol *Imp = find(Name.substr(strlen("__imp_")));
+      if (Imp && isa<Defined>(Imp->body())) {
+        auto *D = cast<Defined>(Imp->body());
+        replaceBody<DefinedLocalImport>(Sym, Name, D);
+        LocalImportChunks.push_back(
+            cast<DefinedLocalImport>(Sym->body())->getChunk());
+        continue;
+      }
+    }
+    // Remaining undefined symbols are not fatal if /force is specified.
+    // They are replaced with dummy defined symbols.
+    if (Config->Force)
+      replaceBody<DefinedAbsolute>(Sym, Name, 0);
+    Undefs.insert(Sym->body());
+  }
+  if (Undefs.empty())
+    return;
+  for (SymbolBody *B : Config->GCRoot)
+    if (Undefs.count(B))
+      warn("<root>: undefined symbol: " + B->getName());
+  for (ObjectFile *File : ObjectFiles)
+    for (SymbolBody *Sym : File->getSymbols())
+      if (Undefs.count(Sym))
+        warn(toString(File) + ": undefined symbol: " + Sym->getName());
+  if (!Config->Force)
+    fatal("link failed");
+}
+
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+  Symbol *&Sym = Symtab[CachedHashStringRef(Name)];
+  if (Sym)
+    return {Sym, false};
+  Sym = make<Symbol>();
+  Sym->IsUsedInRegularObj = false;
+  Sym->PendingArchiveLoad = false;
+  return {Sym, true};
+}
+
+Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F,
+                                  bool IsWeakAlias) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  if (!F || !isa<BitcodeFile>(F))
+    S->IsUsedInRegularObj = true;
+  if (WasInserted || (isa<Lazy>(S->body()) && IsWeakAlias)) {
+    replaceBody<Undefined>(S, Name);
+    return S;
+  }
+  if (auto *L = dyn_cast<Lazy>(S->body())) {
+    if (!S->PendingArchiveLoad) {
+      S->PendingArchiveLoad = true;
+      L->File->addMember(&L->Sym);
+    }
+  }
+  return S;
+}
+
+void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
+  StringRef Name = Sym.getName();
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  if (WasInserted) {
+    replaceBody<Lazy>(S, F, Sym);
+    return;
+  }
+  auto *U = dyn_cast<Undefined>(S->body());
+  if (!U || U->WeakAlias || S->PendingArchiveLoad)
+    return;
+  S->PendingArchiveLoad = true;
+  F->addMember(&Sym);
+}
+
+void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
+  error("duplicate symbol: " + toString(*Existing->body()) + " in " +
+        toString(Existing->body()->getFile()) + " and in " +
+        (NewFile ? toString(NewFile) : "(internal)"));
+}
+
+Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(N);
+  S->IsUsedInRegularObj = true;
+  if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
+    replaceBody<DefinedAbsolute>(S, N, Sym);
+  else if (!isa<DefinedCOFF>(S->body()))
+    reportDuplicate(S, nullptr);
+  return S;
+}
+
+Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(N);
+  S->IsUsedInRegularObj = true;
+  if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
+    replaceBody<DefinedAbsolute>(S, N, VA);
+  else if (!isa<DefinedCOFF>(S->body()))
+    reportDuplicate(S, nullptr);
+  return S;
+}
+
+Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(N);
+  S->IsUsedInRegularObj = true;
+  if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
+    replaceBody<DefinedSynthetic>(S, N, C);
+  else if (!isa<DefinedCOFF>(S->body()))
+    reportDuplicate(S, nullptr);
+  return S;
+}
+
+Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+                                const coff_symbol_generic *Sym,
+                                SectionChunk *C) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(N);
+  if (!isa<BitcodeFile>(F))
+    S->IsUsedInRegularObj = true;
+  SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT);
+  if (SP == SP_CONFLICT) {
+    reportDuplicate(S, F);
+  } else if (SP == SP_NEW) {
+    replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
+  } else if (SP == SP_EXISTING && IsCOMDAT && C) {
+    C->markDiscarded();
+    // Discard associative chunks that we've parsed so far. No need to recurse
+    // because an associative section cannot have children.
+    for (SectionChunk *Child : C->children())
+      Child->markDiscarded();
+  }
+  return S;
+}
+
+Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
+                               const coff_symbol_generic *Sym, CommonChunk *C) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(N);
+  if (!isa<BitcodeFile>(F))
+    S->IsUsedInRegularObj = true;
+  if (WasInserted || !isa<DefinedCOFF>(S->body()))
+    replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
+  else if (auto *DC = dyn_cast<DefinedCommon>(S->body()))
+    if (Size > DC->getSize())
+      replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
+  return S;
+}
+
+Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(N);
+  S->IsUsedInRegularObj = true;
+  if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
+    replaceBody<DefinedImportData>(S, N, F);
+  else if (!isa<DefinedCOFF>(S->body()))
+    reportDuplicate(S, nullptr);
+  return S;
+}
+
+Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
+                                    uint16_t Machine) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  S->IsUsedInRegularObj = true;
+  if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
+    replaceBody<DefinedImportThunk>(S, Name, ID, Machine);
+  else if (!isa<DefinedCOFF>(S->body()))
+    reportDuplicate(S, nullptr);
+  return S;
+}
+
+std::vector<Chunk *> SymbolTable::getChunks() {
+  std::vector<Chunk *> Res;
+  for (ObjectFile *File : ObjectFiles) {
+    std::vector<Chunk *> &V = File->getChunks();
+    Res.insert(Res.end(), V.begin(), V.end());
+  }
+  return Res;
+}
+
+Symbol *SymbolTable::find(StringRef Name) {
+  auto It = Symtab.find(CachedHashStringRef(Name));
+  if (It == Symtab.end())
+    return nullptr;
+  return It->second;
+}
+
+Symbol *SymbolTable::findUnderscore(StringRef Name) {
+  if (Config->Machine == I386)
+    return find(("_" + Name).str());
+  return find(Name);
+}
+
+StringRef SymbolTable::findByPrefix(StringRef Prefix) {
+  for (auto Pair : Symtab) {
+    StringRef Name = Pair.first.val();
+    if (Name.startswith(Prefix))
+      return Name;
+  }
+  return "";
+}
+
+StringRef SymbolTable::findMangle(StringRef Name) {
+  if (Symbol *Sym = find(Name))
+    if (!isa<Undefined>(Sym->body()))
+      return Name;
+  if (Config->Machine != I386)
+    return findByPrefix(("?" + Name + "@@Y").str());
+  if (!Name.startswith("_"))
+    return "";
+  // Search for x86 C function.
+  StringRef S = findByPrefix((Name + "@").str());
+  if (!S.empty())
+    return S;
+  // Search for x86 C++ non-member function.
+  return findByPrefix(("?" + Name.substr(1) + "@@Y").str());
+}
+
+void SymbolTable::mangleMaybe(SymbolBody *B) {
+  auto *U = dyn_cast<Undefined>(B);
+  if (!U || U->WeakAlias)
+    return;
+  StringRef Alias = findMangle(U->getName());
+  if (!Alias.empty())
+    U->WeakAlias = addUndefined(Alias);
+}
+
+SymbolBody *SymbolTable::addUndefined(StringRef Name) {
+  return addUndefined(Name, nullptr, false)->body();
+}
+
+std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
+  LTO.reset(new BitcodeCompiler);
+  for (BitcodeFile *F : BitcodeFiles)
+    LTO->add(*F);
+  return LTO->compile();
+}
+
+void SymbolTable::addCombinedLTOObjects() {
+  if (BitcodeFiles.empty())
+    return;
+  for (StringRef Object : compileBitcodeFiles()) {
+    auto *Obj = make<ObjectFile>(MemoryBufferRef(Object, "lto.tmp"));
+    Obj->parse();
+    ObjectFiles.push_back(Obj);
+  }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
new file mode 100644 (file)
index 0000000..ea74678
--- /dev/null
@@ -0,0 +1,124 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOL_TABLE_H
+#define LLD_COFF_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "LTO.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+struct LTOCodeGenerator;
+}
+
+namespace lld {
+namespace coff {
+
+class Chunk;
+class CommonChunk;
+class Defined;
+class DefinedAbsolute;
+class DefinedRelative;
+class Lazy;
+class SectionChunk;
+class SymbolBody;
+struct Symbol;
+
+// SymbolTable is a bucket of all known symbols, including defined,
+// undefined, or lazy symbols (the last one is symbols in archive
+// files whose archive members are not yet loaded).
+//
+// We put all symbols of all files to a SymbolTable, and the
+// SymbolTable selects the "best" symbols if there are name
+// conflicts. For example, obviously, a defined symbol is better than
+// an undefined symbol. Or, if there's a conflict between a lazy and a
+// undefined, it'll read an archive member to read a real definition
+// to replace the lazy symbol. The logic is implemented in the
+// add*() functions, which are called by input files as they are parsed.
+// There is one add* function per symbol type.
+class SymbolTable {
+public:
+  void addFile(InputFile *File);
+
+  // Try to resolve any undefined symbols and update the symbol table
+  // accordingly, then print an error message for any remaining undefined
+  // symbols.
+  void reportRemainingUndefines();
+
+  // Returns a list of chunks of selected symbols.
+  std::vector<Chunk *> getChunks();
+
+  // Returns a symbol for a given name. Returns a nullptr if not found.
+  Symbol *find(StringRef Name);
+  Symbol *findUnderscore(StringRef Name);
+
+  // Occasionally we have to resolve an undefined symbol to its
+  // mangled symbol. This function tries to find a mangled name
+  // for U from the symbol table, and if found, set the symbol as
+  // a weak alias for U.
+  void mangleMaybe(SymbolBody *B);
+  StringRef findMangle(StringRef Name);
+
+  // Build a set of COFF objects representing the combined contents of
+  // BitcodeFiles and add them to the symbol table. Called after all files are
+  // added and before the writer writes results to a file.
+  void addCombinedLTOObjects();
+  std::vector<StringRef> compileBitcodeFiles();
+
+  // The writer needs to handle DLL import libraries specially in
+  // order to create the import descriptor table.
+  std::vector<ImportFile *> ImportFiles;
+
+  // The writer needs to infer the machine type from the object files.
+  std::vector<ObjectFile *> ObjectFiles;
+
+  // Creates an Undefined symbol for a given name.
+  SymbolBody *addUndefined(StringRef Name);
+
+  Symbol *addSynthetic(StringRef N, Chunk *C);
+  Symbol *addAbsolute(StringRef N, uint64_t VA);
+
+  Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
+  void addLazy(ArchiveFile *F, const Archive::Symbol Sym);
+  Symbol *addAbsolute(StringRef N, COFFSymbolRef S);
+  Symbol *addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+                     const llvm::object::coff_symbol_generic *S = nullptr,
+                     SectionChunk *C = nullptr);
+  Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
+                    const llvm::object::coff_symbol_generic *S = nullptr,
+                    CommonChunk *C = nullptr);
+  Symbol *addImportData(StringRef N, ImportFile *F);
+  Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
+                         uint16_t Machine);
+
+  void reportDuplicate(Symbol *Existing, InputFile *NewFile);
+
+  // A list of chunks which to be added to .rdata.
+  std::vector<Chunk *> LocalImportChunks;
+
+private:
+  std::pair<Symbol *, bool> insert(StringRef Name);
+  StringRef findByPrefix(StringRef Prefix);
+
+  llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> Symtab;
+
+  std::vector<BitcodeFile *> BitcodeFiles;
+  std::unique_ptr<BitcodeCompiler> LTO;
+};
+
+extern SymbolTable *Symtab;
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
new file mode 100644 (file)
index 0000000..9b59079
--- /dev/null
@@ -0,0 +1,90 @@
+//===- Symbols.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Memory.h"
+#include "Strings.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+// Returns a symbol name for an error message.
+std::string lld::toString(coff::SymbolBody &B) {
+  if (Optional<std::string> S = coff::demangle(B.getName()))
+    return ("\"" + *S + "\" (" + B.getName() + ")").str();
+  return B.getName();
+}
+
+namespace lld {
+namespace coff {
+
+StringRef SymbolBody::getName() {
+  // COFF symbol names are read lazily for a performance reason.
+  // Non-external symbol names are never used by the linker except for logging
+  // or debugging. Their internal references are resolved not by name but by
+  // symbol index. And because they are not external, no one can refer them by
+  // name. Object files contain lots of non-external symbols, and creating
+  // StringRefs for them (which involves lots of strlen() on the string table)
+  // is a waste of time.
+  if (Name.empty()) {
+    auto *D = cast<DefinedCOFF>(this);
+    cast<ObjectFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name);
+  }
+  return Name;
+}
+
+InputFile *SymbolBody::getFile() {
+  if (auto *Sym = dyn_cast<DefinedCOFF>(this))
+    return Sym->File;
+  if (auto *Sym = dyn_cast<Lazy>(this))
+    return Sym->File;
+  return nullptr;
+}
+
+COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
+  size_t SymSize =
+      cast<ObjectFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
+  if (SymSize == sizeof(coff_symbol16))
+    return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
+  assert(SymSize == sizeof(coff_symbol32));
+  return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
+}
+
+uint16_t DefinedAbsolute::OutputSectionIndex = 0;
+
+static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
+  if (Machine == AMD64)
+    return make<ImportThunkChunkX64>(S);
+  if (Machine == I386)
+    return make<ImportThunkChunkX86>(S);
+  if (Machine == ARM64)
+    return make<ImportThunkChunkARM64>(S);
+  assert(Machine == ARMNT);
+  return make<ImportThunkChunkARM>(S);
+}
+
+DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,
+                                       uint16_t Machine)
+    : Defined(DefinedImportThunkKind, Name), WrappedSym(S),
+      Data(makeImportThunk(S, Machine)) {}
+
+Defined *Undefined::getWeakAlias() {
+  // A weak alias may be a weak alias to another symbol, so check recursively.
+  for (SymbolBody *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias)
+    if (auto *D = dyn_cast<Defined>(A))
+      return D;
+  return nullptr;
+}
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Symbols.h b/COFF/Symbols.h
new file mode 100644 (file)
index 0000000..a12ae1c
--- /dev/null
@@ -0,0 +1,443 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOLS_H
+#define LLD_COFF_SYMBOLS_H
+
+#include "Chunks.h"
+#include "Config.h"
+#include "Memory.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include <atomic>
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::object::Archive;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_import_header;
+using llvm::object::coff_symbol_generic;
+
+class ArchiveFile;
+class InputFile;
+class ObjectFile;
+struct Symbol;
+class SymbolTable;
+
+// The base class for real symbol classes.
+class SymbolBody {
+public:
+  enum Kind {
+    // The order of these is significant. We start with the regular defined
+    // symbols as those are the most prevelant and the zero tag is the cheapest
+    // to set. Among the defined kinds, the lower the kind is preferred over
+    // the higher kind when testing wether one symbol should take precedence
+    // over another.
+    DefinedRegularKind = 0,
+    DefinedCommonKind,
+    DefinedLocalImportKind,
+    DefinedImportThunkKind,
+    DefinedImportDataKind,
+    DefinedAbsoluteKind,
+    DefinedSyntheticKind,
+
+    UndefinedKind,
+    LazyKind,
+
+    LastDefinedCOFFKind = DefinedCommonKind,
+    LastDefinedKind = DefinedSyntheticKind,
+  };
+
+  Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+  // Returns true if this is an external symbol.
+  bool isExternal() { return IsExternal; }
+
+  // Returns the symbol name.
+  StringRef getName();
+
+  // Returns the file from which this symbol was created.
+  InputFile *getFile();
+
+  Symbol *symbol();
+  const Symbol *symbol() const {
+    return const_cast<SymbolBody *>(this)->symbol();
+  }
+
+protected:
+  friend SymbolTable;
+  explicit SymbolBody(Kind K, StringRef N = "")
+      : SymbolKind(K), IsExternal(true), IsCOMDAT(false),
+        WrittenToSymtab(false), Name(N) {}
+
+  const unsigned SymbolKind : 8;
+  unsigned IsExternal : 1;
+
+  // This bit is used by the \c DefinedRegular subclass.
+  unsigned IsCOMDAT : 1;
+
+public:
+  // This bit is used by Writer::createSymbolAndStringTable() to prevent
+  // symbols from being written to the symbol table more than once.
+  unsigned WrittenToSymtab : 1;
+
+protected:
+  StringRef Name;
+};
+
+// The base class for any defined symbols, including absolute symbols,
+// etc.
+class Defined : public SymbolBody {
+public:
+  Defined(Kind K, StringRef N) : SymbolBody(K, N) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() <= LastDefinedKind;
+  }
+
+  // Returns the RVA (relative virtual address) of this symbol. The
+  // writer sets and uses RVAs.
+  uint64_t getRVA();
+
+  // Returns the chunk containing this symbol. Absolute symbols and __ImageBase
+  // do not have chunks, so this may return null.
+  Chunk *getChunk();
+};
+
+// Symbols defined via a COFF object file or bitcode file.  For COFF files, this
+// stores a coff_symbol_generic*, and names of internal symbols are lazily
+// loaded through that. For bitcode files, Sym is nullptr and the name is stored
+// as a StringRef.
+class DefinedCOFF : public Defined {
+  friend SymbolBody;
+public:
+  DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S)
+      : Defined(K, N), File(F), Sym(S) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() <= LastDefinedCOFFKind;
+  }
+
+  InputFile *getFile() { return File; }
+
+  COFFSymbolRef getCOFFSymbol();
+
+  InputFile *File;
+
+protected:
+  const coff_symbol_generic *Sym;
+};
+
+// Regular defined symbols read from object file symbol tables.
+class DefinedRegular : public DefinedCOFF {
+public:
+  DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+                 bool IsExternal = false,
+                 const coff_symbol_generic *S = nullptr,
+                 SectionChunk *C = nullptr)
+      : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) {
+    this->IsExternal = IsExternal;
+    this->IsCOMDAT = IsCOMDAT;
+  }
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedRegularKind;
+  }
+
+  uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; }
+  bool isCOMDAT() { return IsCOMDAT; }
+  SectionChunk *getChunk() { return *Data; }
+  uint32_t getValue() { return Sym->Value; }
+
+private:
+  SectionChunk **Data;
+};
+
+class DefinedCommon : public DefinedCOFF {
+public:
+  DefinedCommon(InputFile *F, StringRef N, uint64_t Size,
+                const coff_symbol_generic *S = nullptr,
+                CommonChunk *C = nullptr)
+      : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) {
+    this->IsExternal = true;
+  }
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedCommonKind;
+  }
+
+  uint64_t getRVA() { return Data->getRVA(); }
+  Chunk *getChunk() { return Data; }
+
+private:
+  friend SymbolTable;
+  uint64_t getSize() const { return Size; }
+  CommonChunk *Data;
+  uint64_t Size;
+};
+
+// Absolute symbols.
+class DefinedAbsolute : public Defined {
+public:
+  DefinedAbsolute(StringRef N, COFFSymbolRef S)
+      : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) {
+    IsExternal = S.isExternal();
+  }
+
+  DefinedAbsolute(StringRef N, uint64_t V)
+      : Defined(DefinedAbsoluteKind, N), VA(V) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedAbsoluteKind;
+  }
+
+  uint64_t getRVA() { return VA - Config->ImageBase; }
+  void setVA(uint64_t V) { VA = V; }
+
+  // The sentinel absolute symbol section index. Section index relocations
+  // against absolute symbols resolve to this 16 bit number, and it is the
+  // largest valid section index plus one. This is written by the Writer.
+  static uint16_t OutputSectionIndex;
+  uint16_t getSecIdx() { return OutputSectionIndex; }
+
+private:
+  uint64_t VA;
+};
+
+// This symbol is used for linker-synthesized symbols like __ImageBase and
+// __safe_se_handler_table.
+class DefinedSynthetic : public Defined {
+public:
+  explicit DefinedSynthetic(StringRef Name, Chunk *C)
+      : Defined(DefinedSyntheticKind, Name), C(C) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedSyntheticKind;
+  }
+
+  // A null chunk indicates that this is __ImageBase. Otherwise, this is some
+  // other synthesized chunk, like SEHTableChunk.
+  uint32_t getRVA() { return C ? C->getRVA() : 0; }
+  Chunk *getChunk() { return C; }
+
+private:
+  Chunk *C;
+};
+
+// This class represents a symbol defined in an archive file. It is
+// created from an archive file header, and it knows how to load an
+// object file from an archive to replace itself with a defined
+// symbol. If the resolver finds both Undefined and Lazy for
+// the same name, it will ask the Lazy to load a file.
+class Lazy : public SymbolBody {
+public:
+  Lazy(ArchiveFile *F, const Archive::Symbol S)
+      : SymbolBody(LazyKind, S.getName()), File(F), Sym(S) {}
+
+  static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
+
+  ArchiveFile *File;
+
+private:
+  friend SymbolTable;
+
+private:
+  const Archive::Symbol Sym;
+};
+
+// Undefined symbols.
+class Undefined : public SymbolBody {
+public:
+  explicit Undefined(StringRef N) : SymbolBody(UndefinedKind, N) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == UndefinedKind;
+  }
+
+  // An undefined symbol can have a fallback symbol which gives an
+  // undefined symbol a second chance if it would remain undefined.
+  // If it remains undefined, it'll be replaced with whatever the
+  // Alias pointer points to.
+  SymbolBody *WeakAlias = nullptr;
+
+  // If this symbol is external weak, try to resolve it to a defined
+  // symbol by searching the chain of fallback symbols. Returns the symbol if
+  // successful, otherwise returns null.
+  Defined *getWeakAlias();
+};
+
+// Windows-specific classes.
+
+// This class represents a symbol imported from a DLL. This has two
+// names for internal use and external use. The former is used for
+// name resolution, and the latter is used for the import descriptor
+// table in an output. The former has "__imp_" prefix.
+class DefinedImportData : public Defined {
+public:
+  DefinedImportData(StringRef N, ImportFile *F)
+      : Defined(DefinedImportDataKind, N), File(F) {
+  }
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedImportDataKind;
+  }
+
+  uint64_t getRVA() { return File->Location->getRVA(); }
+  Chunk *getChunk() { return File->Location; }
+  void setLocation(Chunk *AddressTable) { File->Location = AddressTable; }
+
+  StringRef getDLLName() { return File->DLLName; }
+  StringRef getExternalName() { return File->ExternalName; }
+  uint16_t getOrdinal() { return File->Hdr->OrdinalHint; }
+
+  ImportFile *File;
+};
+
+// This class represents a symbol for a jump table entry which jumps
+// to a function in a DLL. Linker are supposed to create such symbols
+// without "__imp_" prefix for all function symbols exported from
+// DLLs, so that you can call DLL functions as regular functions with
+// a regular name. A function pointer is given as a DefinedImportData.
+class DefinedImportThunk : public Defined {
+public:
+  DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedImportThunkKind;
+  }
+
+  uint64_t getRVA() { return Data->getRVA(); }
+  Chunk *getChunk() { return Data; }
+
+  DefinedImportData *WrappedSym;
+
+private:
+  Chunk *Data;
+};
+
+// If you have a symbol "__imp_foo" in your object file, a symbol name
+// "foo" becomes automatically available as a pointer to "__imp_foo".
+// This class is for such automatically-created symbols.
+// Yes, this is an odd feature. We didn't intend to implement that.
+// This is here just for compatibility with MSVC.
+class DefinedLocalImport : public Defined {
+public:
+  DefinedLocalImport(StringRef N, Defined *S)
+      : Defined(DefinedLocalImportKind, N), Data(make<LocalImportChunk>(S)) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedLocalImportKind;
+  }
+
+  uint64_t getRVA() { return Data->getRVA(); }
+  Chunk *getChunk() { return Data; }
+
+private:
+  LocalImportChunk *Data;
+};
+
+inline uint64_t Defined::getRVA() {
+  switch (kind()) {
+  case DefinedAbsoluteKind:
+    return cast<DefinedAbsolute>(this)->getRVA();
+  case DefinedSyntheticKind:
+    return cast<DefinedSynthetic>(this)->getRVA();
+  case DefinedImportDataKind:
+    return cast<DefinedImportData>(this)->getRVA();
+  case DefinedImportThunkKind:
+    return cast<DefinedImportThunk>(this)->getRVA();
+  case DefinedLocalImportKind:
+    return cast<DefinedLocalImport>(this)->getRVA();
+  case DefinedCommonKind:
+    return cast<DefinedCommon>(this)->getRVA();
+  case DefinedRegularKind:
+    return cast<DefinedRegular>(this)->getRVA();
+  case LazyKind:
+  case UndefinedKind:
+    llvm_unreachable("Cannot get the address for an undefined symbol.");
+  }
+  llvm_unreachable("unknown symbol kind");
+}
+
+inline Chunk *Defined::getChunk() {
+  switch (kind()) {
+  case DefinedRegularKind:
+    return cast<DefinedRegular>(this)->getChunk();
+  case DefinedAbsoluteKind:
+    return nullptr;
+  case DefinedSyntheticKind:
+    return cast<DefinedSynthetic>(this)->getChunk();
+  case DefinedImportDataKind:
+    return cast<DefinedImportData>(this)->getChunk();
+  case DefinedImportThunkKind:
+    return cast<DefinedImportThunk>(this)->getChunk();
+  case DefinedLocalImportKind:
+    return cast<DefinedLocalImport>(this)->getChunk();
+  case DefinedCommonKind:
+    return cast<DefinedCommon>(this)->getChunk();
+  case LazyKind:
+  case UndefinedKind:
+    llvm_unreachable("Cannot get the chunk of an undefined symbol.");
+  }
+  llvm_unreachable("unknown symbol kind");
+}
+
+// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
+// always one Symbol for each symbol name. The resolver updates the SymbolBody
+// stored in the Body field of this object as it resolves symbols. Symbol also
+// holds computed properties of symbol names.
+struct Symbol {
+  // True if this symbol was referenced by a regular (non-bitcode) object.
+  unsigned IsUsedInRegularObj : 1;
+
+  // True if we've seen both a lazy and an undefined symbol with this symbol
+  // name, which means that we have enqueued an archive member load and should
+  // not load any more archive members to resolve the same symbol.
+  unsigned PendingArchiveLoad : 1;
+
+  // This field is used to store the Symbol's SymbolBody. This instantiation of
+  // AlignedCharArrayUnion gives us a struct with a char array field that is
+  // large and aligned enough to store any derived class of SymbolBody.
+  llvm::AlignedCharArrayUnion<
+      DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedSynthetic, Lazy,
+      Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport>
+      Body;
+
+  SymbolBody *body() {
+    return reinterpret_cast<SymbolBody *>(Body.buffer);
+  }
+  const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); }
+};
+
+template <typename T, typename... ArgT>
+void replaceBody(Symbol *S, ArgT &&... Arg) {
+  static_assert(sizeof(T) <= sizeof(S->Body), "Body too small");
+  static_assert(alignof(T) <= alignof(decltype(S->Body)),
+                "Body not aligned enough");
+  assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr &&
+         "Not a SymbolBody");
+  new (S->Body.buffer) T(std::forward<ArgT>(Arg)...);
+}
+
+inline Symbol *SymbolBody::symbol() {
+  assert(isExternal());
+  return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) -
+                                    offsetof(Symbol, Body));
+}
+} // namespace coff
+
+std::string toString(coff::SymbolBody &B);
+} // namespace lld
+
+#endif
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
new file mode 100644 (file)
index 0000000..a6a5e27
--- /dev/null
@@ -0,0 +1,900 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Writer.h"
+#include "Config.h"
+#include "DLL.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "MapFile.h"
+#include "Memory.h"
+#include "PDB.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdio>
+#include <map>
+#include <memory>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::coff;
+
+static const int SectorSize = 512;
+static const int DOSStubSize = 64;
+static const int NumberfOfDataDirectory = 16;
+
+namespace {
+
+class DebugDirectoryChunk : public Chunk {
+public:
+  DebugDirectoryChunk(const std::vector<Chunk *> &R) : Records(R) {}
+
+  size_t getSize() const override {
+    return Records.size() * sizeof(debug_directory);
+  }
+
+  void writeTo(uint8_t *B) const override {
+    auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff);
+
+    for (const Chunk *Record : Records) {
+      D->Characteristics = 0;
+      D->TimeDateStamp = 0;
+      D->MajorVersion = 0;
+      D->MinorVersion = 0;
+      D->Type = COFF::IMAGE_DEBUG_TYPE_CODEVIEW;
+      D->SizeOfData = Record->getSize();
+      D->AddressOfRawData = Record->getRVA();
+      // TODO(compnerd) get the file offset
+      D->PointerToRawData = 0;
+
+      ++D;
+    }
+  }
+
+private:
+  const std::vector<Chunk *> &Records;
+};
+
+class CVDebugRecordChunk : public Chunk {
+  size_t getSize() const override {
+    return sizeof(codeview::DebugInfo) + Config->PDBPath.size() + 1;
+  }
+
+  void writeTo(uint8_t *B) const override {
+    // Save off the DebugInfo entry to backfill the file signature (build id)
+    // in Writer::writeBuildId
+    DI = reinterpret_cast<codeview::DebugInfo *>(B + OutputSectionOff);
+
+    DI->Signature.CVSignature = OMF::Signature::PDB70;
+
+    // variable sized field (PDB Path)
+    auto *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*DI));
+    if (!Config->PDBPath.empty())
+      memcpy(P, Config->PDBPath.data(), Config->PDBPath.size());
+    P[Config->PDBPath.size()] = '\0';
+  }
+
+public:
+  mutable codeview::DebugInfo *DI = nullptr;
+};
+
+// The writer writes a SymbolTable result to a file.
+class Writer {
+public:
+  Writer(SymbolTable *T) : Symtab(T) {}
+  void run();
+
+private:
+  void createSections();
+  void createMiscChunks();
+  void createImportTables();
+  void createExportTable();
+  void assignAddresses();
+  void removeEmptySections();
+  void createSymbolAndStringTable();
+  void openFile(StringRef OutputPath);
+  template <typename PEHeaderTy> void writeHeader();
+  void fixSafeSEHSymbols();
+  void setSectionPermissions();
+  void writeSections();
+  void sortExceptionTable();
+  void writeBuildId();
+
+  llvm::Optional<coff_symbol16> createSymbol(Defined *D);
+  size_t addEntryToStringTable(StringRef Str);
+
+  OutputSection *findSection(StringRef Name);
+  OutputSection *createSection(StringRef Name);
+  void addBaserels(OutputSection *Dest);
+  void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
+
+  uint32_t getSizeOfInitializedData();
+  std::map<StringRef, std::vector<DefinedImportData *>> binImports();
+
+  SymbolTable *Symtab;
+  std::unique_ptr<FileOutputBuffer> Buffer;
+  std::vector<OutputSection *> OutputSections;
+  std::vector<char> Strtab;
+  std::vector<llvm::object::coff_symbol16> OutputSymtab;
+  IdataContents Idata;
+  DelayLoadContents DelayIdata;
+  EdataContents Edata;
+  SEHTableChunk *SEHTable = nullptr;
+
+  Chunk *DebugDirectory = nullptr;
+  std::vector<Chunk *> DebugRecords;
+  CVDebugRecordChunk *BuildId = nullptr;
+  ArrayRef<uint8_t> SectionTable;
+
+  uint64_t FileSize;
+  uint32_t PointerToSymbolTable = 0;
+  uint64_t SizeOfImage;
+  uint64_t SizeOfHeaders;
+};
+} // anonymous namespace
+
+namespace lld {
+namespace coff {
+
+void writeResult(SymbolTable *T) { Writer(T).run(); }
+
+void OutputSection::setRVA(uint64_t RVA) {
+  Header.VirtualAddress = RVA;
+  for (Chunk *C : Chunks)
+    C->setRVA(C->getRVA() + RVA);
+}
+
+void OutputSection::setFileOffset(uint64_t Off) {
+  // If a section has no actual data (i.e. BSS section), we want to
+  // set 0 to its PointerToRawData. Otherwise the output is rejected
+  // by the loader.
+  if (Header.SizeOfRawData == 0)
+    return;
+  Header.PointerToRawData = Off;
+}
+
+void OutputSection::addChunk(Chunk *C) {
+  Chunks.push_back(C);
+  C->setOutputSection(this);
+  uint64_t Off = Header.VirtualSize;
+  Off = alignTo(Off, C->getAlign());
+  C->setRVA(Off);
+  C->OutputSectionOff = Off;
+  Off += C->getSize();
+  Header.VirtualSize = Off;
+  if (C->hasData())
+    Header.SizeOfRawData = alignTo(Off, SectorSize);
+}
+
+void OutputSection::addPermissions(uint32_t C) {
+  Header.Characteristics |= C & PermMask;
+}
+
+void OutputSection::setPermissions(uint32_t C) {
+  Header.Characteristics = C & PermMask;
+}
+
+// Write the section header to a given buffer.
+void OutputSection::writeHeaderTo(uint8_t *Buf) {
+  auto *Hdr = reinterpret_cast<coff_section *>(Buf);
+  *Hdr = Header;
+  if (StringTableOff) {
+    // If name is too long, write offset into the string table as a name.
+    sprintf(Hdr->Name, "/%d", StringTableOff);
+  } else {
+    assert(!Config->Debug || Name.size() <= COFF::NameSize);
+    strncpy(Hdr->Name, Name.data(),
+            std::min(Name.size(), (size_t)COFF::NameSize));
+  }
+}
+
+} // namespace coff
+} // namespace lld
+
+// The main function of the writer.
+void Writer::run() {
+  createSections();
+  createMiscChunks();
+  createImportTables();
+  createExportTable();
+  if (Config->Relocatable)
+    createSection(".reloc");
+  assignAddresses();
+  removeEmptySections();
+  setSectionPermissions();
+  createSymbolAndStringTable();
+  openFile(Config->OutputFile);
+  if (Config->is64()) {
+    writeHeader<pe32plus_header>();
+  } else {
+    writeHeader<pe32_header>();
+  }
+  fixSafeSEHSymbols();
+  writeSections();
+  sortExceptionTable();
+  writeBuildId();
+
+  if (!Config->PDBPath.empty() && Config->Debug) {
+    const llvm::codeview::DebugInfo *DI = nullptr;
+    if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
+      DI = BuildId->DI;
+    createPDB(Symtab, SectionTable, DI);
+  }
+
+  writeMapFile(OutputSections);
+
+  if (auto EC = Buffer->commit())
+    fatal(EC, "failed to write the output file");
+}
+
+static StringRef getOutputSection(StringRef Name) {
+  StringRef S = Name.split('$').first;
+  auto It = Config->Merge.find(S);
+  if (It == Config->Merge.end())
+    return S;
+  return It->second;
+}
+
+// Create output section objects and add them to OutputSections.
+void Writer::createSections() {
+  // First, bin chunks by name.
+  std::map<StringRef, std::vector<Chunk *>> Map;
+  for (Chunk *C : Symtab->getChunks()) {
+    auto *SC = dyn_cast<SectionChunk>(C);
+    if (SC && !SC->isLive()) {
+      if (Config->Verbose)
+        SC->printDiscardedMessage();
+      continue;
+    }
+    Map[C->getSectionName()].push_back(C);
+  }
+
+  // Then create an OutputSection for each section.
+  // '$' and all following characters in input section names are
+  // discarded when determining output section. So, .text$foo
+  // contributes to .text, for example. See PE/COFF spec 3.2.
+  SmallDenseMap<StringRef, OutputSection *> Sections;
+  for (auto Pair : Map) {
+    StringRef Name = getOutputSection(Pair.first);
+    OutputSection *&Sec = Sections[Name];
+    if (!Sec) {
+      Sec = make<OutputSection>(Name);
+      OutputSections.push_back(Sec);
+    }
+    std::vector<Chunk *> &Chunks = Pair.second;
+    for (Chunk *C : Chunks) {
+      Sec->addChunk(C);
+      Sec->addPermissions(C->getPermissions());
+    }
+  }
+}
+
+void Writer::createMiscChunks() {
+  OutputSection *RData = createSection(".rdata");
+
+  // Create thunks for locally-dllimported symbols.
+  if (!Symtab->LocalImportChunks.empty()) {
+    for (Chunk *C : Symtab->LocalImportChunks)
+      RData->addChunk(C);
+  }
+
+  // Create Debug Information Chunks
+  if (Config->Debug) {
+    DebugDirectory = make<DebugDirectoryChunk>(DebugRecords);
+
+    // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled
+    if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) {
+      auto *Chunk = make<CVDebugRecordChunk>();
+
+      BuildId = Chunk;
+      DebugRecords.push_back(Chunk);
+    }
+
+    RData->addChunk(DebugDirectory);
+    for (Chunk *C : DebugRecords)
+      RData->addChunk(C);
+  }
+
+  // Create SEH table. x86-only.
+  if (Config->Machine != I386)
+    return;
+
+  std::set<Defined *> Handlers;
+
+  for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
+    if (!File->SEHCompat)
+      return;
+    for (SymbolBody *B : File->SEHandlers) {
+      // Make sure the handler is still live. Assume all handlers are regular
+      // symbols.
+      auto *D = dyn_cast<DefinedRegular>(B);
+      if (D && D->getChunk()->isLive())
+        Handlers.insert(D);
+    }
+  }
+
+  if (!Handlers.empty()) {
+    SEHTable = make<SEHTableChunk>(Handlers);
+    RData->addChunk(SEHTable);
+  }
+}
+
+// Create .idata section for the DLL-imported symbol table.
+// The format of this section is inherently Windows-specific.
+// IdataContents class abstracted away the details for us,
+// so we just let it create chunks and add them to the section.
+void Writer::createImportTables() {
+  if (Symtab->ImportFiles.empty())
+    return;
+
+  // Initialize DLLOrder so that import entries are ordered in
+  // the same order as in the command line. (That affects DLL
+  // initialization order, and this ordering is MSVC-compatible.)
+  for (ImportFile *File : Symtab->ImportFiles) {
+    if (!File->Live)
+      continue;
+
+    std::string DLL = StringRef(File->DLLName).lower();
+    if (Config->DLLOrder.count(DLL) == 0)
+      Config->DLLOrder[DLL] = Config->DLLOrder.size();
+  }
+
+  OutputSection *Text = createSection(".text");
+  for (ImportFile *File : Symtab->ImportFiles) {
+    if (!File->Live)
+      continue;
+
+    if (DefinedImportThunk *Thunk = File->ThunkSym)
+      Text->addChunk(Thunk->getChunk());
+
+    if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
+      if (!File->ThunkSym)
+        fatal("cannot delay-load " + toString(File) +
+              " due to import of data: " + toString(*File->ImpSym));
+      DelayIdata.add(File->ImpSym);
+    } else {
+      Idata.add(File->ImpSym);
+    }
+  }
+
+  if (!Idata.empty()) {
+    OutputSection *Sec = createSection(".idata");
+    for (Chunk *C : Idata.getChunks())
+      Sec->addChunk(C);
+  }
+
+  if (!DelayIdata.empty()) {
+    Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
+    DelayIdata.create(Helper);
+    OutputSection *Sec = createSection(".didat");
+    for (Chunk *C : DelayIdata.getChunks())
+      Sec->addChunk(C);
+    Sec = createSection(".data");
+    for (Chunk *C : DelayIdata.getDataChunks())
+      Sec->addChunk(C);
+    Sec = createSection(".text");
+    for (Chunk *C : DelayIdata.getCodeChunks())
+      Sec->addChunk(C);
+  }
+}
+
+void Writer::createExportTable() {
+  if (Config->Exports.empty())
+    return;
+  OutputSection *Sec = createSection(".edata");
+  for (Chunk *C : Edata.Chunks)
+    Sec->addChunk(C);
+}
+
+// The Windows loader doesn't seem to like empty sections,
+// so we remove them if any.
+void Writer::removeEmptySections() {
+  auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; };
+  OutputSections.erase(
+      std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty),
+      OutputSections.end());
+  uint32_t Idx = 1;
+  for (OutputSection *Sec : OutputSections)
+    Sec->SectionIndex = Idx++;
+}
+
+size_t Writer::addEntryToStringTable(StringRef Str) {
+  assert(Str.size() > COFF::NameSize);
+  size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field
+  Strtab.insert(Strtab.end(), Str.begin(), Str.end());
+  Strtab.push_back('\0');
+  return OffsetOfEntry;
+}
+
+Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
+  // Relative symbols are unrepresentable in a COFF symbol table.
+  if (isa<DefinedSynthetic>(Def))
+    return None;
+
+  if (auto *D = dyn_cast<DefinedRegular>(Def)) {
+    // Don't write dead symbols or symbols in codeview sections to the symbol
+    // table.
+    if (!D->getChunk()->isLive() || D->getChunk()->isCodeView())
+      return None;
+  }
+
+  if (auto *Sym = dyn_cast<DefinedImportData>(Def))
+    if (!Sym->File->Live)
+      return None;
+
+  if (auto *Sym = dyn_cast<DefinedImportThunk>(Def))
+    if (!Sym->WrappedSym->File->Live)
+      return None;
+
+  coff_symbol16 Sym;
+  StringRef Name = Def->getName();
+  if (Name.size() > COFF::NameSize) {
+    Sym.Name.Offset.Zeroes = 0;
+    Sym.Name.Offset.Offset = addEntryToStringTable(Name);
+  } else {
+    memset(Sym.Name.ShortName, 0, COFF::NameSize);
+    memcpy(Sym.Name.ShortName, Name.data(), Name.size());
+  }
+
+  if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
+    COFFSymbolRef Ref = D->getCOFFSymbol();
+    Sym.Type = Ref.getType();
+    Sym.StorageClass = Ref.getStorageClass();
+  } else {
+    Sym.Type = IMAGE_SYM_TYPE_NULL;
+    Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
+  }
+  Sym.NumberOfAuxSymbols = 0;
+
+  switch (Def->kind()) {
+  case SymbolBody::DefinedAbsoluteKind:
+    Sym.Value = Def->getRVA();
+    Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+    break;
+  default: {
+    uint64_t RVA = Def->getRVA();
+    OutputSection *Sec = nullptr;
+    for (OutputSection *S : OutputSections) {
+      if (S->getRVA() > RVA)
+        break;
+      Sec = S;
+    }
+    Sym.Value = RVA - Sec->getRVA();
+    Sym.SectionNumber = Sec->SectionIndex;
+    break;
+  }
+  }
+  return Sym;
+}
+
+void Writer::createSymbolAndStringTable() {
+  if (!Config->Debug || !Config->WriteSymtab)
+    return;
+
+  // Name field in the section table is 8 byte long. Longer names need
+  // to be written to the string table. First, construct string table.
+  for (OutputSection *Sec : OutputSections) {
+    StringRef Name = Sec->getName();
+    if (Name.size() <= COFF::NameSize)
+      continue;
+    Sec->setStringTableOff(addEntryToStringTable(Name));
+  }
+
+  for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
+    for (SymbolBody *B : File->getSymbols()) {
+      auto *D = dyn_cast<Defined>(B);
+      if (!D || D->WrittenToSymtab)
+        continue;
+      D->WrittenToSymtab = true;
+
+      if (Optional<coff_symbol16> Sym = createSymbol(D))
+        OutputSymtab.push_back(*Sym);
+    }
+  }
+
+  OutputSection *LastSection = OutputSections.back();
+  // We position the symbol table to be adjacent to the end of the last section.
+  uint64_t FileOff = LastSection->getFileOff() +
+                     alignTo(LastSection->getRawSize(), SectorSize);
+  if (!OutputSymtab.empty()) {
+    PointerToSymbolTable = FileOff;
+    FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
+  }
+  if (!Strtab.empty())
+    FileOff += Strtab.size() + 4;
+  FileSize = alignTo(FileOff, SectorSize);
+}
+
+// Visits all sections to assign incremental, non-overlapping RVAs and
+// file offsets.
+void Writer::assignAddresses() {
+  SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
+                  sizeof(data_directory) * NumberfOfDataDirectory +
+                  sizeof(coff_section) * OutputSections.size();
+  SizeOfHeaders +=
+      Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
+  SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
+  uint64_t RVA = 0x1000; // The first page is kept unmapped.
+  FileSize = SizeOfHeaders;
+  // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
+  // the loader cannot handle holes.
+  std::stable_partition(
+      OutputSections.begin(), OutputSections.end(), [](OutputSection *S) {
+        return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0;
+      });
+  for (OutputSection *Sec : OutputSections) {
+    if (Sec->getName() == ".reloc")
+      addBaserels(Sec);
+    Sec->setRVA(RVA);
+    Sec->setFileOffset(FileSize);
+    RVA += alignTo(Sec->getVirtualSize(), PageSize);
+    FileSize += alignTo(Sec->getRawSize(), SectorSize);
+  }
+  SizeOfImage = SizeOfHeaders + alignTo(RVA - 0x1000, PageSize);
+}
+
+template <typename PEHeaderTy> void Writer::writeHeader() {
+  // Write DOS stub
+  uint8_t *Buf = Buffer->getBufferStart();
+  auto *DOS = reinterpret_cast<dos_header *>(Buf);
+  Buf += DOSStubSize;
+  DOS->Magic[0] = 'M';
+  DOS->Magic[1] = 'Z';
+  DOS->AddressOfRelocationTable = sizeof(dos_header);
+  DOS->AddressOfNewExeHeader = DOSStubSize;
+
+  // Write PE magic
+  memcpy(Buf, PEMagic, sizeof(PEMagic));
+  Buf += sizeof(PEMagic);
+
+  // Write COFF header
+  auto *COFF = reinterpret_cast<coff_file_header *>(Buf);
+  Buf += sizeof(*COFF);
+  COFF->Machine = Config->Machine;
+  COFF->NumberOfSections = OutputSections.size();
+  COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
+  if (Config->LargeAddressAware)
+    COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+  if (!Config->is64())
+    COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
+  if (Config->DLL)
+    COFF->Characteristics |= IMAGE_FILE_DLL;
+  if (!Config->Relocatable)
+    COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+  COFF->SizeOfOptionalHeader =
+      sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory;
+
+  // Write PE header
+  auto *PE = reinterpret_cast<PEHeaderTy *>(Buf);
+  Buf += sizeof(*PE);
+  PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
+
+  // If {Major,Minor}LinkerVersion is left at 0.0, then for some
+  // reason signing the resulting PE file with Authenticode produces a
+  // signature that fails to validate on Windows 7 (but is OK on 10).
+  // Set it to 14.0, which is what VS2015 outputs, and which avoids
+  // that problem.
+  PE->MajorLinkerVersion = 14;
+  PE->MinorLinkerVersion = 0;
+
+  PE->ImageBase = Config->ImageBase;
+  PE->SectionAlignment = PageSize;
+  PE->FileAlignment = SectorSize;
+  PE->MajorImageVersion = Config->MajorImageVersion;
+  PE->MinorImageVersion = Config->MinorImageVersion;
+  PE->MajorOperatingSystemVersion = Config->MajorOSVersion;
+  PE->MinorOperatingSystemVersion = Config->MinorOSVersion;
+  PE->MajorSubsystemVersion = Config->MajorOSVersion;
+  PE->MinorSubsystemVersion = Config->MinorOSVersion;
+  PE->Subsystem = Config->Subsystem;
+  PE->SizeOfImage = SizeOfImage;
+  PE->SizeOfHeaders = SizeOfHeaders;
+  if (!Config->NoEntry) {
+    Defined *Entry = cast<Defined>(Config->Entry);
+    PE->AddressOfEntryPoint = Entry->getRVA();
+    // Pointer to thumb code must have the LSB set, so adjust it.
+    if (Config->Machine == ARMNT)
+      PE->AddressOfEntryPoint |= 1;
+  }
+  PE->SizeOfStackReserve = Config->StackReserve;
+  PE->SizeOfStackCommit = Config->StackCommit;
+  PE->SizeOfHeapReserve = Config->HeapReserve;
+  PE->SizeOfHeapCommit = Config->HeapCommit;
+
+  // Import Descriptor Tables and Import Address Tables are merged
+  // in our output. That's not compatible with the Binding feature
+  // that is sort of prelinking. Setting this flag to make it clear
+  // that our outputs are not for the Binding.
+  PE->DLLCharacteristics = IMAGE_DLL_CHARACTERISTICS_NO_BIND;
+
+  if (Config->AppContainer)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
+  if (Config->DynamicBase)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
+  if (Config->HighEntropyVA)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
+  if (Config->NxCompat)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
+  if (!Config->AllowIsolation)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
+  if (Config->TerminalServerAware)
+    PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
+  PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
+  if (OutputSection *Text = findSection(".text")) {
+    PE->BaseOfCode = Text->getRVA();
+    PE->SizeOfCode = Text->getRawSize();
+  }
+  PE->SizeOfInitializedData = getSizeOfInitializedData();
+
+  // Write data directory
+  auto *Dir = reinterpret_cast<data_directory *>(Buf);
+  Buf += sizeof(*Dir) * NumberfOfDataDirectory;
+  if (OutputSection *Sec = findSection(".edata")) {
+    Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (!Idata.empty()) {
+    Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
+    Dir[IMPORT_TABLE].Size = Idata.getDirSize();
+    Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
+    Dir[IAT].Size = Idata.getIATSize();
+  }
+  if (OutputSection *Sec = findSection(".rsrc")) {
+    Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (OutputSection *Sec = findSection(".pdata")) {
+    Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (OutputSection *Sec = findSection(".reloc")) {
+    Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
+    Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+  }
+  if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
+    if (Defined *B = dyn_cast<Defined>(Sym->body())) {
+      Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA();
+      Dir[TLS_TABLE].Size = Config->is64()
+                                ? sizeof(object::coff_tls_directory64)
+                                : sizeof(object::coff_tls_directory32);
+    }
+  }
+  if (Config->Debug) {
+    Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA();
+    Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize();
+  }
+  if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) {
+    if (auto *B = dyn_cast<DefinedRegular>(Sym->body())) {
+      SectionChunk *SC = B->getChunk();
+      assert(B->getRVA() >= SC->getRVA());
+      uint64_t OffsetInChunk = B->getRVA() - SC->getRVA();
+      if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize())
+        fatal("_load_config_used is malformed");
+
+      ArrayRef<uint8_t> SecContents = SC->getContents();
+      uint32_t LoadConfigSize =
+          *reinterpret_cast<const ulittle32_t *>(&SecContents[OffsetInChunk]);
+      if (OffsetInChunk + LoadConfigSize > SC->getSize())
+        fatal("_load_config_used is too large");
+      Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA();
+      Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize;
+    }
+  }
+  if (!DelayIdata.empty()) {
+    Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
+        DelayIdata.getDirRVA();
+    Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize();
+  }
+
+  // Write section table
+  for (OutputSection *Sec : OutputSections) {
+    Sec->writeHeaderTo(Buf);
+    Buf += sizeof(coff_section);
+  }
+  SectionTable = ArrayRef<uint8_t>(
+      Buf - OutputSections.size() * sizeof(coff_section), Buf);
+
+  if (OutputSymtab.empty())
+    return;
+
+  COFF->PointerToSymbolTable = PointerToSymbolTable;
+  uint32_t NumberOfSymbols = OutputSymtab.size();
+  COFF->NumberOfSymbols = NumberOfSymbols;
+  auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(
+      Buffer->getBufferStart() + COFF->PointerToSymbolTable);
+  for (size_t I = 0; I != NumberOfSymbols; ++I)
+    SymbolTable[I] = OutputSymtab[I];
+  // Create the string table, it follows immediately after the symbol table.
+  // The first 4 bytes is length including itself.
+  Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]);
+  write32le(Buf, Strtab.size() + 4);
+  if (!Strtab.empty())
+    memcpy(Buf + 4, Strtab.data(), Strtab.size());
+}
+
+void Writer::openFile(StringRef Path) {
+  Buffer = check(
+      FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable),
+      "failed to open " + Path);
+}
+
+void Writer::fixSafeSEHSymbols() {
+  if (!SEHTable)
+    return;
+  // Replace the absolute table symbol with a synthetic symbol pointing to the
+  // SEHTable chunk so that we can emit base relocations for it and resolve
+  // section relative relocations.
+  Symbol *T = Symtab->find("___safe_se_handler_table");
+  Symbol *C = Symtab->find("___safe_se_handler_count");
+  replaceBody<DefinedSynthetic>(T, T->body()->getName(), SEHTable);
+  cast<DefinedAbsolute>(C->body())->setVA(SEHTable->getSize() / 4);
+}
+
+// Handles /section options to allow users to overwrite
+// section attributes.
+void Writer::setSectionPermissions() {
+  for (auto &P : Config->Section) {
+    StringRef Name = P.first;
+    uint32_t Perm = P.second;
+    if (auto *Sec = findSection(Name))
+      Sec->setPermissions(Perm);
+  }
+}
+
+// Write section contents to a mmap'ed file.
+void Writer::writeSections() {
+  // Record the section index that should be used when resolving a section
+  // relocation against an absolute symbol.
+  DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1;
+
+  uint8_t *Buf = Buffer->getBufferStart();
+  for (OutputSection *Sec : OutputSections) {
+    uint8_t *SecBuf = Buf + Sec->getFileOff();
+    // Fill gaps between functions in .text with INT3 instructions
+    // instead of leaving as NUL bytes (which can be interpreted as
+    // ADD instructions).
+    if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE)
+      memset(SecBuf, 0xCC, Sec->getRawSize());
+    for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
+             [&](Chunk *C) { C->writeTo(SecBuf); });
+  }
+}
+
+// Sort .pdata section contents according to PE/COFF spec 5.5.
+void Writer::sortExceptionTable() {
+  OutputSection *Sec = findSection(".pdata");
+  if (!Sec)
+    return;
+  // We assume .pdata contains function table entries only.
+  uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
+  uint8_t *End = Begin + Sec->getVirtualSize();
+  if (Config->Machine == AMD64) {
+    struct Entry { ulittle32_t Begin, End, Unwind; };
+    sort(parallel::par, (Entry *)Begin, (Entry *)End,
+         [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+    return;
+  }
+  if (Config->Machine == ARMNT) {
+    struct Entry { ulittle32_t Begin, Unwind; };
+    sort(parallel::par, (Entry *)Begin, (Entry *)End,
+         [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+    return;
+  }
+  errs() << "warning: don't know how to handle .pdata.\n";
+}
+
+// Backfill the CVSignature in a PDB70 Debug Record.  This backfilling allows us
+// to get reproducible builds.
+void Writer::writeBuildId() {
+  // There is nothing to backfill if BuildId was not setup.
+  if (BuildId == nullptr)
+    return;
+
+  assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 &&
+         "only PDB 7.0 is supported");
+  assert(sizeof(BuildId->DI->PDB70.Signature) == 16 &&
+         "signature size mismatch");
+
+  // Compute an MD5 hash.
+  ArrayRef<uint8_t> Buf(Buffer->getBufferStart(), Buffer->getBufferEnd());
+  memcpy(BuildId->DI->PDB70.Signature, MD5::hash(Buf).data(), 16);
+
+  // TODO(compnerd) track the Age
+  BuildId->DI->PDB70.Age = 1;
+}
+
+OutputSection *Writer::findSection(StringRef Name) {
+  for (OutputSection *Sec : OutputSections)
+    if (Sec->getName() == Name)
+      return Sec;
+  return nullptr;
+}
+
+uint32_t Writer::getSizeOfInitializedData() {
+  uint32_t Res = 0;
+  for (OutputSection *S : OutputSections)
+    if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA)
+      Res += S->getRawSize();
+  return Res;
+}
+
+// Returns an existing section or create a new one if not found.
+OutputSection *Writer::createSection(StringRef Name) {
+  if (auto *Sec = findSection(Name))
+    return Sec;
+  const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+  const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+  const auto CODE = IMAGE_SCN_CNT_CODE;
+  const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+  const auto R = IMAGE_SCN_MEM_READ;
+  const auto W = IMAGE_SCN_MEM_WRITE;
+  const auto X = IMAGE_SCN_MEM_EXECUTE;
+  uint32_t Perms = StringSwitch<uint32_t>(Name)
+                       .Case(".bss", BSS | R | W)
+                       .Case(".data", DATA | R | W)
+                       .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R)
+                       .Case(".reloc", DATA | DISCARDABLE | R)
+                       .Case(".text", CODE | R | X)
+                       .Default(0);
+  if (!Perms)
+    llvm_unreachable("unknown section name");
+  auto Sec = make<OutputSection>(Name);
+  Sec->addPermissions(Perms);
+  OutputSections.push_back(Sec);
+  return Sec;
+}
+
+// Dest is .reloc section. Add contents to that section.
+void Writer::addBaserels(OutputSection *Dest) {
+  std::vector<Baserel> V;
+  for (OutputSection *Sec : OutputSections) {
+    if (Sec == Dest)
+      continue;
+    // Collect all locations for base relocations.
+    for (Chunk *C : Sec->getChunks())
+      C->getBaserels(&V);
+    // Add the addresses to .reloc section.
+    if (!V.empty())
+      addBaserelBlocks(Dest, V);
+    V.clear();
+  }
+}
+
+// Add addresses to .reloc section. Note that addresses are grouped by page.
+void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
+  const uint32_t Mask = ~uint32_t(PageSize - 1);
+  uint32_t Page = V[0].RVA & Mask;
+  size_t I = 0, J = 1;
+  for (size_t E = V.size(); J < E; ++J) {
+    uint32_t P = V[J].RVA & Mask;
+    if (P == Page)
+      continue;
+    Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+    I = J;
+    Page = P;
+  }
+  if (I == J)
+    return;
+  Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+}
diff --git a/COFF/Writer.h b/COFF/Writer.h
new file mode 100644 (file)
index 0000000..fef5754
--- /dev/null
@@ -0,0 +1,75 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_WRITER_H
+#define LLD_COFF_WRITER_H
+
+#include "Chunks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <cstdint>
+#include <vector>
+
+namespace lld {
+namespace coff {
+class SymbolTable;
+
+static const int PageSize = 4096;
+
+void writeResult(SymbolTable *T);
+
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+  OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
+  void setRVA(uint64_t);
+  void setFileOffset(uint64_t);
+  void addChunk(Chunk *C);
+  llvm::StringRef getName() { return Name; }
+  std::vector<Chunk *> &getChunks() { return Chunks; }
+  void addPermissions(uint32_t C);
+  void setPermissions(uint32_t C);
+  uint32_t getPermissions() { return Header.Characteristics & PermMask; }
+  uint32_t getCharacteristics() { return Header.Characteristics; }
+  uint64_t getRVA() { return Header.VirtualAddress; }
+  uint64_t getFileOff() { return Header.PointerToRawData; }
+  void writeHeaderTo(uint8_t *Buf);
+
+  // Returns the size of this section in an executable memory image.
+  // This may be smaller than the raw size (the raw size is multiple
+  // of disk sector size, so there may be padding at end), or may be
+  // larger (if that's the case, the loader reserves spaces after end
+  // of raw data).
+  uint64_t getVirtualSize() { return Header.VirtualSize; }
+
+  // Returns the size of the section in the output file.
+  uint64_t getRawSize() { return Header.SizeOfRawData; }
+
+  // Set offset into the string table storing this section name.
+  // Used only when the name is longer than 8 bytes.
+  void setStringTableOff(uint32_t V) { StringTableOff = V; }
+
+  // N.B. The section index is one based.
+  uint32_t SectionIndex = 0;
+
+private:
+  llvm::StringRef Name;
+  llvm::object::coff_section Header;
+  uint32_t StringTableOff = 0;
+  std::vector<Chunk *> Chunks;
+};
+
+}
+}
+
+#endif
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp
new file mode 100644 (file)
index 0000000..b26cf08
--- /dev/null
@@ -0,0 +1,376 @@
+//===- AArch64.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+// Page(Expr) is the page address of the expression Expr, defined
+// as (Expr & ~0xFFF). (This applies even if the machine page size
+// supported by the platform has a different value.)
+uint64_t elf::getAArch64Page(uint64_t Expr) {
+  return Expr & ~static_cast<uint64_t>(0xFFF);
+}
+
+namespace {
+class AArch64 final : public TargetInfo {
+public:
+  AArch64();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  bool isPicRel(uint32_t Type) const override;
+  void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+  void writePltHeader(uint8_t *Buf) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  bool usesOnlyLowPageBits(uint32_t Type) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                          RelExpr Expr) const override;
+  void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+AArch64::AArch64() {
+  CopyRel = R_AARCH64_COPY;
+  RelativeRel = R_AARCH64_RELATIVE;
+  IRelativeRel = R_AARCH64_IRELATIVE;
+  GotRel = R_AARCH64_GLOB_DAT;
+  PltRel = R_AARCH64_JUMP_SLOT;
+  TlsDescRel = R_AARCH64_TLSDESC;
+  TlsGotRel = R_AARCH64_TLS_TPREL64;
+  GotEntrySize = 8;
+  GotPltEntrySize = 8;
+  PltEntrySize = 16;
+  PltHeaderSize = 32;
+  DefaultMaxPageSize = 65536;
+
+  // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
+  // 1 of the tls structures and the tcb size is 16.
+  TcbSize = 16;
+}
+
+RelExpr AArch64::getRelExpr(uint32_t Type, const SymbolBody &S,
+                            const uint8_t *Loc) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_AARCH64_TLSDESC_ADR_PAGE21:
+    return R_TLSDESC_PAGE;
+  case R_AARCH64_TLSDESC_LD64_LO12:
+  case R_AARCH64_TLSDESC_ADD_LO12:
+    return R_TLSDESC;
+  case R_AARCH64_TLSDESC_CALL:
+    return R_TLSDESC_CALL;
+  case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+  case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+    return R_TLS;
+  case R_AARCH64_CALL26:
+  case R_AARCH64_CONDBR19:
+  case R_AARCH64_JUMP26:
+  case R_AARCH64_TSTBR14:
+    return R_PLT_PC;
+  case R_AARCH64_PREL16:
+  case R_AARCH64_PREL32:
+  case R_AARCH64_PREL64:
+  case R_AARCH64_ADR_PREL_LO21:
+    return R_PC;
+  case R_AARCH64_ADR_PREL_PG_HI21:
+    return R_PAGE_PC;
+  case R_AARCH64_LD64_GOT_LO12_NC:
+  case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+    return R_GOT;
+  case R_AARCH64_ADR_GOT_PAGE:
+  case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    return R_GOT_PAGE_PC;
+  case R_AARCH64_NONE:
+    return R_NONE;
+  }
+}
+
+RelExpr AArch64::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                                 RelExpr Expr) const {
+  if (Expr == R_RELAX_TLS_GD_TO_IE) {
+    if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
+      return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
+    return R_RELAX_TLS_GD_TO_IE_ABS;
+  }
+  return Expr;
+}
+
+bool AArch64::usesOnlyLowPageBits(uint32_t Type) const {
+  switch (Type) {
+  default:
+    return false;
+  case R_AARCH64_ADD_ABS_LO12_NC:
+  case R_AARCH64_LD64_GOT_LO12_NC:
+  case R_AARCH64_LDST128_ABS_LO12_NC:
+  case R_AARCH64_LDST16_ABS_LO12_NC:
+  case R_AARCH64_LDST32_ABS_LO12_NC:
+  case R_AARCH64_LDST64_ABS_LO12_NC:
+  case R_AARCH64_LDST8_ABS_LO12_NC:
+  case R_AARCH64_TLSDESC_ADD_LO12:
+  case R_AARCH64_TLSDESC_LD64_LO12:
+  case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+    return true;
+  }
+}
+
+bool AArch64::isPicRel(uint32_t Type) const {
+  return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
+}
+
+void AArch64::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+  write64le(Buf, InX::Plt->getVA());
+}
+
+void AArch64::writePltHeader(uint8_t *Buf) const {
+  const uint8_t PltData[] = {
+      0xf0, 0x7b, 0xbf, 0xa9, // stp    x16, x30, [sp,#-16]!
+      0x10, 0x00, 0x00, 0x90, // adrp   x16, Page(&(.plt.got[2]))
+      0x11, 0x02, 0x40, 0xf9, // ldr    x17, [x16, Offset(&(.plt.got[2]))]
+      0x10, 0x02, 0x00, 0x91, // add    x16, x16, Offset(&(.plt.got[2]))
+      0x20, 0x02, 0x1f, 0xd6, // br     x17
+      0x1f, 0x20, 0x03, 0xd5, // nop
+      0x1f, 0x20, 0x03, 0xd5, // nop
+      0x1f, 0x20, 0x03, 0xd5  // nop
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+
+  uint64_t Got = InX::GotPlt->getVA();
+  uint64_t Plt = InX::Plt->getVA();
+  relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
+              getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
+  relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
+  relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
+}
+
+void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+                       uint64_t PltEntryAddr, int32_t Index,
+                       unsigned RelOff) const {
+  const uint8_t Inst[] = {
+      0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
+      0x11, 0x02, 0x40, 0xf9, // ldr  x17, [x16, Offset(&(.plt.got[n]))]
+      0x10, 0x02, 0x00, 0x91, // add  x16, x16, Offset(&(.plt.got[n]))
+      0x20, 0x02, 0x1f, 0xd6  // br   x17
+  };
+  memcpy(Buf, Inst, sizeof(Inst));
+
+  relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
+              getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr));
+  relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr);
+  relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr);
+}
+
+static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
+  uint32_t ImmLo = (Imm & 0x3) << 29;
+  uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
+  uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
+  write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
+}
+
+// Return the bits [Start, End] from Val shifted Start bits.
+// For instance, getBits(0xF0, 4, 8) returns 0xF.
+static uint64_t getBits(uint64_t Val, int Start, int End) {
+  uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1;
+  return (Val >> Start) & Mask;
+}
+
+static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+
+// Update the immediate field in a AARCH64 ldr, str, and add instruction.
+static void or32AArch64Imm(uint8_t *L, uint64_t Imm) {
+  or32le(L, (Imm & 0xFFF) << 10);
+}
+
+void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  switch (Type) {
+  case R_AARCH64_ABS16:
+  case R_AARCH64_PREL16:
+    checkIntUInt<16>(Loc, Val, Type);
+    write16le(Loc, Val);
+    break;
+  case R_AARCH64_ABS32:
+  case R_AARCH64_PREL32:
+    checkIntUInt<32>(Loc, Val, Type);
+    write32le(Loc, Val);
+    break;
+  case R_AARCH64_ABS64:
+  case R_AARCH64_GLOB_DAT:
+  case R_AARCH64_PREL64:
+    write64le(Loc, Val);
+    break;
+  case R_AARCH64_ADD_ABS_LO12_NC:
+    or32AArch64Imm(Loc, Val);
+    break;
+  case R_AARCH64_ADR_GOT_PAGE:
+  case R_AARCH64_ADR_PREL_PG_HI21:
+  case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+  case R_AARCH64_TLSDESC_ADR_PAGE21:
+    checkInt<33>(Loc, Val, Type);
+    write32AArch64Addr(Loc, Val >> 12);
+    break;
+  case R_AARCH64_ADR_PREL_LO21:
+    checkInt<21>(Loc, Val, Type);
+    write32AArch64Addr(Loc, Val);
+    break;
+  case R_AARCH64_CALL26:
+  case R_AARCH64_JUMP26:
+    checkInt<28>(Loc, Val, Type);
+    or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
+    break;
+  case R_AARCH64_CONDBR19:
+    checkInt<21>(Loc, Val, Type);
+    or32le(Loc, (Val & 0x1FFFFC) << 3);
+    break;
+  case R_AARCH64_LD64_GOT_LO12_NC:
+  case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+  case R_AARCH64_TLSDESC_LD64_LO12:
+    checkAlignment<8>(Loc, Val, Type);
+    or32le(Loc, (Val & 0xFF8) << 7);
+    break;
+  case R_AARCH64_LDST8_ABS_LO12_NC:
+    or32AArch64Imm(Loc, getBits(Val, 0, 11));
+    break;
+  case R_AARCH64_LDST16_ABS_LO12_NC:
+    or32AArch64Imm(Loc, getBits(Val, 1, 11));
+    break;
+  case R_AARCH64_LDST32_ABS_LO12_NC:
+    or32AArch64Imm(Loc, getBits(Val, 2, 11));
+    break;
+  case R_AARCH64_LDST64_ABS_LO12_NC:
+    or32AArch64Imm(Loc, getBits(Val, 3, 11));
+    break;
+  case R_AARCH64_LDST128_ABS_LO12_NC:
+    or32AArch64Imm(Loc, getBits(Val, 4, 11));
+    break;
+  case R_AARCH64_MOVW_UABS_G0_NC:
+    or32le(Loc, (Val & 0xFFFF) << 5);
+    break;
+  case R_AARCH64_MOVW_UABS_G1_NC:
+    or32le(Loc, (Val & 0xFFFF0000) >> 11);
+    break;
+  case R_AARCH64_MOVW_UABS_G2_NC:
+    or32le(Loc, (Val & 0xFFFF00000000) >> 27);
+    break;
+  case R_AARCH64_MOVW_UABS_G3:
+    or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
+    break;
+  case R_AARCH64_TSTBR14:
+    checkInt<16>(Loc, Val, Type);
+    or32le(Loc, (Val & 0xFFFC) << 3);
+    break;
+  case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    checkInt<24>(Loc, Val, Type);
+    or32AArch64Imm(Loc, Val >> 12);
+    break;
+  case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+  case R_AARCH64_TLSDESC_ADD_LO12:
+    or32AArch64Imm(Loc, Val);
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+void AArch64::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  // TLSDESC Global-Dynamic relocation are in the form:
+  //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
+  //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
+  //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
+  //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
+  //   blr     x1
+  // And it can optimized to:
+  //   movz    x0, #0x0, lsl #16
+  //   movk    x0, #0x10
+  //   nop
+  //   nop
+  checkUInt<32>(Loc, Val, Type);
+
+  switch (Type) {
+  case R_AARCH64_TLSDESC_ADD_LO12:
+  case R_AARCH64_TLSDESC_CALL:
+    write32le(Loc, 0xd503201f); // nop
+    return;
+  case R_AARCH64_TLSDESC_ADR_PAGE21:
+    write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz
+    return;
+  case R_AARCH64_TLSDESC_LD64_LO12:
+    write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk
+    return;
+  default:
+    llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+  }
+}
+
+void AArch64::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  // TLSDESC Global-Dynamic relocation are in the form:
+  //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
+  //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12]
+  //   add     x0, x0, :tlsdesc_los:v     [R_AARCH64_TLSDESC_ADD_LO12]
+  //   .tlsdesccall                       [R_AARCH64_TLSDESC_CALL]
+  //   blr     x1
+  // And it can optimized to:
+  //   adrp    x0, :gottprel:v
+  //   ldr     x0, [x0, :gottprel_lo12:v]
+  //   nop
+  //   nop
+
+  switch (Type) {
+  case R_AARCH64_TLSDESC_ADD_LO12:
+  case R_AARCH64_TLSDESC_CALL:
+    write32le(Loc, 0xd503201f); // nop
+    break;
+  case R_AARCH64_TLSDESC_ADR_PAGE21:
+    write32le(Loc, 0x90000000); // adrp
+    relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val);
+    break;
+  case R_AARCH64_TLSDESC_LD64_LO12:
+    write32le(Loc, 0xf9400000); // ldr
+    relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val);
+    break;
+  default:
+    llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+  }
+}
+
+void AArch64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  checkUInt<32>(Loc, Val, Type);
+
+  if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
+    // Generate MOVZ.
+    uint32_t RegNo = read32le(Loc) & 0x1f;
+    write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5));
+    return;
+  }
+  if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
+    // Generate MOVK.
+    uint32_t RegNo = read32le(Loc) & 0x1f;
+    write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5));
+    return;
+  }
+  llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
+}
+
+TargetInfo *elf::getAArch64TargetInfo() {
+  static AArch64 Target;
+  return &Target;
+}
diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp
new file mode 100644 (file)
index 0000000..de566c6
--- /dev/null
@@ -0,0 +1,84 @@
+//===- AMDGPU.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class AMDGPU final : public TargetInfo {
+public:
+  AMDGPU();
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+};
+} // namespace
+
+AMDGPU::AMDGPU() {
+  RelativeRel = R_AMDGPU_REL64;
+  GotRel = R_AMDGPU_ABS64;
+  GotEntrySize = 8;
+}
+
+void AMDGPU::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  switch (Type) {
+  case R_AMDGPU_ABS32:
+  case R_AMDGPU_GOTPCREL:
+  case R_AMDGPU_GOTPCREL32_LO:
+  case R_AMDGPU_REL32:
+  case R_AMDGPU_REL32_LO:
+    write32le(Loc, Val);
+    break;
+  case R_AMDGPU_ABS64:
+    write64le(Loc, Val);
+    break;
+  case R_AMDGPU_GOTPCREL32_HI:
+  case R_AMDGPU_REL32_HI:
+    write32le(Loc, Val >> 32);
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S,
+                           const uint8_t *Loc) const {
+  switch (Type) {
+  case R_AMDGPU_ABS32:
+  case R_AMDGPU_ABS64:
+    return R_ABS;
+  case R_AMDGPU_REL32:
+  case R_AMDGPU_REL32_LO:
+  case R_AMDGPU_REL32_HI:
+    return R_PC;
+  case R_AMDGPU_GOTPCREL:
+  case R_AMDGPU_GOTPCREL32_LO:
+  case R_AMDGPU_GOTPCREL32_HI:
+    return R_GOT_PC;
+  default:
+    error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+    return R_HINT;
+  }
+}
+
+TargetInfo *elf::getAMDGPUTargetInfo() {
+  static AMDGPU Target;
+  return &Target;
+}
diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp
new file mode 100644 (file)
index 0000000..106021d
--- /dev/null
@@ -0,0 +1,480 @@
+//===- ARM.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class ARM final : public TargetInfo {
+public:
+  ARM();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  bool isPicRel(uint32_t Type) const override;
+  uint32_t getDynRel(uint32_t Type) const override;
+  int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+  void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+  void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+  void writePltHeader(uint8_t *Buf) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override;
+  void addPltHeaderSymbols(InputSectionBase *ISD) const override;
+  bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+                  const SymbolBody &S) const override;
+  bool inBranchRange(uint32_t RelocType, uint64_t Src,
+                     uint64_t Dst) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+ARM::ARM() {
+  CopyRel = R_ARM_COPY;
+  RelativeRel = R_ARM_RELATIVE;
+  IRelativeRel = R_ARM_IRELATIVE;
+  GotRel = R_ARM_GLOB_DAT;
+  PltRel = R_ARM_JUMP_SLOT;
+  TlsGotRel = R_ARM_TLS_TPOFF32;
+  TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
+  TlsOffsetRel = R_ARM_TLS_DTPOFF32;
+  GotEntrySize = 4;
+  GotPltEntrySize = 4;
+  PltEntrySize = 16;
+  PltHeaderSize = 20;
+  TrapInstr = 0xd4d4d4d4;
+  // ARM uses Variant 1 TLS
+  TcbSize = 8;
+  NeedsThunks = true;
+}
+
+RelExpr ARM::getRelExpr(uint32_t Type, const SymbolBody &S,
+                        const uint8_t *Loc) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_ARM_THM_JUMP11:
+    return R_PC;
+  case R_ARM_CALL:
+  case R_ARM_JUMP24:
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+  case R_ARM_PREL31:
+  case R_ARM_THM_JUMP19:
+  case R_ARM_THM_JUMP24:
+  case R_ARM_THM_CALL:
+    return R_PLT_PC;
+  case R_ARM_GOTOFF32:
+    // (S + A) - GOT_ORG
+    return R_GOTREL;
+  case R_ARM_GOT_BREL:
+    // GOT(S) + A - GOT_ORG
+    return R_GOT_OFF;
+  case R_ARM_GOT_PREL:
+  case R_ARM_TLS_IE32:
+    // GOT(S) + A - P
+    return R_GOT_PC;
+  case R_ARM_SBREL32:
+    return R_ARM_SBREL;
+  case R_ARM_TARGET1:
+    return Config->Target1Rel ? R_PC : R_ABS;
+  case R_ARM_TARGET2:
+    if (Config->Target2 == Target2Policy::Rel)
+      return R_PC;
+    if (Config->Target2 == Target2Policy::Abs)
+      return R_ABS;
+    return R_GOT_PC;
+  case R_ARM_TLS_GD32:
+    return R_TLSGD_PC;
+  case R_ARM_TLS_LDM32:
+    return R_TLSLD_PC;
+  case R_ARM_BASE_PREL:
+    // B(S) + A - P
+    // FIXME: currently B(S) assumed to be .got, this may not hold for all
+    // platforms.
+    return R_GOTONLY_PC;
+  case R_ARM_MOVW_PREL_NC:
+  case R_ARM_MOVT_PREL:
+  case R_ARM_REL32:
+  case R_ARM_THM_MOVW_PREL_NC:
+  case R_ARM_THM_MOVT_PREL:
+    return R_PC;
+  case R_ARM_NONE:
+    return R_NONE;
+  case R_ARM_TLS_LE32:
+    return R_TLS;
+  }
+}
+
+bool ARM::isPicRel(uint32_t Type) const {
+  return (Type == R_ARM_TARGET1 && !Config->Target1Rel) ||
+         (Type == R_ARM_ABS32);
+}
+
+uint32_t ARM::getDynRel(uint32_t Type) const {
+  if (Type == R_ARM_TARGET1 && !Config->Target1Rel)
+    return R_ARM_ABS32;
+  if (Type == R_ARM_ABS32)
+    return Type;
+  // Keep it going with a dummy value so that we can find more reloc errors.
+  return R_ARM_ABS32;
+}
+
+void ARM::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+  write32le(Buf, InX::Plt->getVA());
+}
+
+void ARM::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+  // An ARM entry is the address of the ifunc resolver function.
+  write32le(Buf, S.getVA());
+}
+
+void ARM::writePltHeader(uint8_t *Buf) const {
+  const uint8_t PltData[] = {
+      0x04, 0xe0, 0x2d, 0xe5, //     str lr, [sp,#-4]!
+      0x04, 0xe0, 0x9f, 0xe5, //     ldr lr, L2
+      0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr
+      0x08, 0xf0, 0xbe, 0xe5, //     ldr pc, [lr, #8]
+      0x00, 0x00, 0x00, 0x00, // L2: .word   &(.got.plt) - L1 - 8
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+  uint64_t GotPlt = InX::GotPlt->getVA();
+  uint64_t L1 = InX::Plt->getVA() + 8;
+  write32le(Buf + 16, GotPlt - L1 - 8);
+}
+
+void ARM::addPltHeaderSymbols(InputSectionBase *ISD) const {
+  auto *IS = cast<InputSection>(ISD);
+  addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS);
+  addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS);
+}
+
+void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+                   uint64_t PltEntryAddr, int32_t Index,
+                   unsigned RelOff) const {
+  // FIXME: Using simple code sequence with simple relocations.
+  // There is a more optimal sequence but it requires support for the group
+  // relocations. See ELF for the ARM Architecture Appendix A.3
+  const uint8_t PltData[] = {
+      0x04, 0xc0, 0x9f, 0xe5, //     ldr ip, L2
+      0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+      0x00, 0xf0, 0x9c, 0xe5, //     ldr pc, [ip]
+      0x00, 0x00, 0x00, 0x00, // L2: .word   Offset(&(.plt.got) - L1 - 8
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+  uint64_t L1 = PltEntryAddr + 4;
+  write32le(Buf + 12, GotPltEntryAddr - L1 - 8);
+}
+
+void ARM::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const {
+  auto *IS = cast<InputSection>(ISD);
+  addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS);
+  addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS);
+}
+
+bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+                     const SymbolBody &S) const {
+  // If S is an undefined weak symbol in an executable we don't need a Thunk.
+  // In a DSO calls to undefined symbols, including weak ones get PLT entries
+  // which may need a thunk.
+  if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
+      !Config->Shared)
+    return false;
+  // A state change from ARM to Thumb and vice versa must go through an
+  // interworking thunk if the relocation type is not R_ARM_CALL or
+  // R_ARM_THM_CALL.
+  switch (RelocType) {
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+  case R_ARM_JUMP24:
+    // Source is ARM, all PLT entries are ARM so no interworking required.
+    // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
+    if (Expr == R_PC && ((S.getVA() & 1) == 1))
+      return true;
+    break;
+  case R_ARM_THM_JUMP19:
+  case R_ARM_THM_JUMP24:
+    // Source is Thumb, all PLT entries are ARM so interworking is required.
+    // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
+    if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0))
+      return true;
+    break;
+  }
+  return false;
+}
+
+bool ARM::inBranchRange(uint32_t RelocType, uint64_t Src, uint64_t Dst) const {
+  uint64_t Range;
+  uint64_t InstrSize;
+
+  switch (RelocType) {
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+  case R_ARM_JUMP24:
+  case R_ARM_CALL:
+    Range = 0x2000000;
+    InstrSize = 4;
+    break;
+  case R_ARM_THM_JUMP19:
+    Range = 0x100000;
+    InstrSize = 2;
+    break;
+  case R_ARM_THM_JUMP24:
+  case R_ARM_THM_CALL:
+    Range = 0x1000000;
+    InstrSize = 2;
+    break;
+  default:
+    return true;
+  }
+  // PC at Src is 2 instructions ahead, immediate of branch is signed
+  if (Src > Dst)
+    Range -= 2 * InstrSize;
+  else
+    Range += InstrSize;
+
+  if ((Dst & 0x1) == 0)
+    // Destination is ARM, if ARM caller then Src is already 4-byte aligned.
+    // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure
+    // destination will be 4 byte aligned.
+    Src &= ~0x3;
+  else
+    // Bit 0 == 1 denotes Thumb state, it is not part of the range
+    Dst &= ~0x1;
+
+  uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src;
+  return Distance <= Range;
+}
+
+void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  switch (Type) {
+  case R_ARM_ABS32:
+  case R_ARM_BASE_PREL:
+  case R_ARM_GLOB_DAT:
+  case R_ARM_GOTOFF32:
+  case R_ARM_GOT_BREL:
+  case R_ARM_GOT_PREL:
+  case R_ARM_REL32:
+  case R_ARM_RELATIVE:
+  case R_ARM_SBREL32:
+  case R_ARM_TARGET1:
+  case R_ARM_TARGET2:
+  case R_ARM_TLS_GD32:
+  case R_ARM_TLS_IE32:
+  case R_ARM_TLS_LDM32:
+  case R_ARM_TLS_LDO32:
+  case R_ARM_TLS_LE32:
+  case R_ARM_TLS_TPOFF32:
+  case R_ARM_TLS_DTPOFF32:
+    write32le(Loc, Val);
+    break;
+  case R_ARM_TLS_DTPMOD32:
+    write32le(Loc, 1);
+    break;
+  case R_ARM_PREL31:
+    checkInt<31>(Loc, Val, Type);
+    write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
+    break;
+  case R_ARM_CALL:
+    // R_ARM_CALL is used for BL and BLX instructions, depending on the
+    // value of bit 0 of Val, we must select a BL or BLX instruction
+    if (Val & 1) {
+      // If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
+      // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
+      checkInt<26>(Loc, Val, Type);
+      write32le(Loc, 0xfa000000 |                    // opcode
+                         ((Val & 2) << 23) |         // H
+                         ((Val >> 2) & 0x00ffffff)); // imm24
+      break;
+    }
+    if ((read32le(Loc) & 0xfe000000) == 0xfa000000)
+      // BLX (always unconditional) instruction to an ARM Target, select an
+      // unconditional BL.
+      write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff));
+    // fall through as BL encoding is shared with B
+    LLVM_FALLTHROUGH;
+  case R_ARM_JUMP24:
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+    checkInt<26>(Loc, Val, Type);
+    write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
+    break;
+  case R_ARM_THM_JUMP11:
+    checkInt<12>(Loc, Val, Type);
+    write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
+    break;
+  case R_ARM_THM_JUMP19:
+    // Encoding T3: Val = S:J2:J1:imm6:imm11:0
+    checkInt<21>(Loc, Val, Type);
+    write16le(Loc,
+              (read16le(Loc) & 0xfbc0) |   // opcode cond
+                  ((Val >> 10) & 0x0400) | // S
+                  ((Val >> 12) & 0x003f)); // imm6
+    write16le(Loc + 2,
+              0x8000 |                    // opcode
+                  ((Val >> 8) & 0x0800) | // J2
+                  ((Val >> 5) & 0x2000) | // J1
+                  ((Val >> 1) & 0x07ff)); // imm11
+    break;
+  case R_ARM_THM_CALL:
+    // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the
+    // value of bit 0 of Val, we must select a BL or BLX instruction
+    if ((Val & 1) == 0) {
+      // Ensure BLX destination is 4-byte aligned. As BLX instruction may
+      // only be two byte aligned. This must be done before overflow check
+      Val = alignTo(Val, 4);
+    }
+    // Bit 12 is 0 for BLX, 1 for BL
+    write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
+    // Fall through as rest of encoding is the same as B.W
+    LLVM_FALLTHROUGH;
+  case R_ARM_THM_JUMP24:
+    // Encoding B  T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
+    // FIXME: Use of I1 and I2 require v6T2ops
+    checkInt<25>(Loc, Val, Type);
+    write16le(Loc,
+              0xf000 |                     // opcode
+                  ((Val >> 14) & 0x0400) | // S
+                  ((Val >> 12) & 0x03ff)); // imm10
+    write16le(Loc + 2,
+              (read16le(Loc + 2) & 0xd000) |                  // opcode
+                  (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1
+                  (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2
+                  ((Val >> 1) & 0x07ff));                     // imm11
+    break;
+  case R_ARM_MOVW_ABS_NC:
+  case R_ARM_MOVW_PREL_NC:
+    write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
+                       (Val & 0x0fff));
+    break;
+  case R_ARM_MOVT_ABS:
+  case R_ARM_MOVT_PREL:
+    checkInt<32>(Loc, Val, Type);
+    write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
+                       (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
+    break;
+  case R_ARM_THM_MOVT_ABS:
+  case R_ARM_THM_MOVT_PREL:
+    // Encoding T1: A = imm4:i:imm3:imm8
+    checkInt<32>(Loc, Val, Type);
+    write16le(Loc,
+              0xf2c0 |                     // opcode
+                  ((Val >> 17) & 0x0400) | // i
+                  ((Val >> 28) & 0x000f)); // imm4
+    write16le(Loc + 2,
+              (read16le(Loc + 2) & 0x8f00) | // opcode
+                  ((Val >> 12) & 0x7000) |   // imm3
+                  ((Val >> 16) & 0x00ff));   // imm8
+    break;
+  case R_ARM_THM_MOVW_ABS_NC:
+  case R_ARM_THM_MOVW_PREL_NC:
+    // Encoding T3: A = imm4:i:imm3:imm8
+    write16le(Loc,
+              0xf240 |                     // opcode
+                  ((Val >> 1) & 0x0400) |  // i
+                  ((Val >> 12) & 0x000f)); // imm4
+    write16le(Loc + 2,
+              (read16le(Loc + 2) & 0x8f00) | // opcode
+                  ((Val << 4) & 0x7000) |    // imm3
+                  (Val & 0x00ff));           // imm8
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+int64_t ARM::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
+  switch (Type) {
+  default:
+    return 0;
+  case R_ARM_ABS32:
+  case R_ARM_BASE_PREL:
+  case R_ARM_GOTOFF32:
+  case R_ARM_GOT_BREL:
+  case R_ARM_GOT_PREL:
+  case R_ARM_REL32:
+  case R_ARM_TARGET1:
+  case R_ARM_TARGET2:
+  case R_ARM_TLS_GD32:
+  case R_ARM_TLS_LDM32:
+  case R_ARM_TLS_LDO32:
+  case R_ARM_TLS_IE32:
+  case R_ARM_TLS_LE32:
+    return SignExtend64<32>(read32le(Buf));
+  case R_ARM_PREL31:
+    return SignExtend64<31>(read32le(Buf));
+  case R_ARM_CALL:
+  case R_ARM_JUMP24:
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+    return SignExtend64<26>(read32le(Buf) << 2);
+  case R_ARM_THM_JUMP11:
+    return SignExtend64<12>(read16le(Buf) << 1);
+  case R_ARM_THM_JUMP19: {
+    // Encoding T3: A = S:J2:J1:imm10:imm6:0
+    uint16_t Hi = read16le(Buf);
+    uint16_t Lo = read16le(Buf + 2);
+    return SignExtend64<20>(((Hi & 0x0400) << 10) | // S
+                            ((Lo & 0x0800) << 8) |  // J2
+                            ((Lo & 0x2000) << 5) |  // J1
+                            ((Hi & 0x003f) << 12) | // imm6
+                            ((Lo & 0x07ff) << 1));  // imm11:0
+  }
+  case R_ARM_THM_CALL:
+  case R_ARM_THM_JUMP24: {
+    // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
+    // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
+    // FIXME: I1 and I2 require v6T2ops
+    uint16_t Hi = read16le(Buf);
+    uint16_t Lo = read16le(Buf + 2);
+    return SignExtend64<24>(((Hi & 0x0400) << 14) |                    // S
+                            (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1
+                            (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2
+                            ((Hi & 0x003ff) << 12) |                   // imm0
+                            ((Lo & 0x007ff) << 1)); // imm11:0
+  }
+  // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
+  // MOVT is in the range -32768 <= A < 32768
+  case R_ARM_MOVW_ABS_NC:
+  case R_ARM_MOVT_ABS:
+  case R_ARM_MOVW_PREL_NC:
+  case R_ARM_MOVT_PREL: {
+    uint64_t Val = read32le(Buf) & 0x000f0fff;
+    return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
+  }
+  case R_ARM_THM_MOVW_ABS_NC:
+  case R_ARM_THM_MOVT_ABS:
+  case R_ARM_THM_MOVW_PREL_NC:
+  case R_ARM_THM_MOVT_PREL: {
+    // Encoding T3: A = imm4:i:imm3:imm8
+    uint16_t Hi = read16le(Buf);
+    uint16_t Lo = read16le(Buf + 2);
+    return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4
+                            ((Hi & 0x0400) << 1) |  // i
+                            ((Lo & 0x7000) >> 4) |  // imm3
+                            (Lo & 0x00ff));         // imm8
+  }
+  }
+}
+
+TargetInfo *elf::getARMTargetInfo() {
+  static ARM Target;
+  return &Target;
+}
diff --git a/ELF/Arch/AVR.cpp b/ELF/Arch/AVR.cpp
new file mode 100644 (file)
index 0000000..3853248
--- /dev/null
@@ -0,0 +1,80 @@
+//===- AVR.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AVR is a Harvard-architecture 8-bit micrcontroller designed for small
+// baremetal programs. All AVR-family processors have 32 8-bit registers.
+// The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest
+// one supports up to 2^24 data address space and 2^22 code address space.
+//
+// Since it is a baremetal programming, there's usually no loader to load
+// ELF files on AVRs. You are expected to link your program against address
+// 0 and pull out a .text section from the result using objcopy, so that you
+// can write the linked code to on-chip flush memory. You can do that with
+// the following commands:
+//
+//   ld.lld -Ttext=0 -o foo foo.o
+//   objcopy -O binary --only-section=.text foo output.bin
+//
+// Note that the current AVR support is very preliminary so you can't
+// link any useful program yet, though.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class AVR final : public TargetInfo {
+public:
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+RelExpr AVR::getRelExpr(uint32_t Type, const SymbolBody &S,
+                        const uint8_t *Loc) const {
+  switch (Type) {
+  case R_AVR_CALL:
+    return R_ABS;
+  default:
+    error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+    return R_HINT;
+  }
+}
+
+void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  switch (Type) {
+  case R_AVR_CALL: {
+    uint16_t Hi = Val >> 17;
+    uint16_t Lo = Val >> 1;
+    write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1));
+    write16le(Loc + 2, Lo);
+    break;
+  }
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+  }
+}
+
+TargetInfo *elf::getAVRTargetInfo() {
+  static AVR Target;
+  return &Target;
+}
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
new file mode 100644 (file)
index 0000000..b8d796f
--- /dev/null
@@ -0,0 +1,423 @@
+//===- MIPS.cpp -----------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+template <class ELFT> class MIPS final : public TargetInfo {
+public:
+  MIPS();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+  bool isPicRel(uint32_t Type) const override;
+  uint32_t getDynRel(uint32_t Type) const override;
+  void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+  void writePltHeader(uint8_t *Buf) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+                  const SymbolBody &S) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  bool usesOnlyLowPageBits(uint32_t Type) const override;
+};
+} // namespace
+
+template <class ELFT> MIPS<ELFT>::MIPS() {
+  GotPltHeaderEntriesNum = 2;
+  DefaultMaxPageSize = 65536;
+  GotEntrySize = sizeof(typename ELFT::uint);
+  GotPltEntrySize = sizeof(typename ELFT::uint);
+  PltEntrySize = 16;
+  PltHeaderSize = 32;
+  CopyRel = R_MIPS_COPY;
+  PltRel = R_MIPS_JUMP_SLOT;
+  NeedsThunks = true;
+  TrapInstr = 0xefefefef;
+
+  if (ELFT::Is64Bits) {
+    RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
+    TlsGotRel = R_MIPS_TLS_TPREL64;
+    TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
+    TlsOffsetRel = R_MIPS_TLS_DTPREL64;
+  } else {
+    RelativeRel = R_MIPS_REL32;
+    TlsGotRel = R_MIPS_TLS_TPREL32;
+    TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
+    TlsOffsetRel = R_MIPS_TLS_DTPREL32;
+  }
+}
+
+template <class ELFT>
+RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
+                               const uint8_t *Loc) const {
+  // See comment in the calculateMipsRelChain.
+  if (ELFT::Is64Bits || Config->MipsN32Abi)
+    Type &= 0xff;
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_MIPS_JALR:
+    return R_HINT;
+  case R_MIPS_GPREL16:
+  case R_MIPS_GPREL32:
+    return R_MIPS_GOTREL;
+  case R_MIPS_26:
+    return R_PLT;
+  case R_MIPS_HI16:
+  case R_MIPS_LO16:
+    // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
+    // offset between start of function and 'gp' value which by default
+    // equal to the start of .got section. In that case we consider these
+    // relocations as relative.
+    if (&S == ElfSym::MipsGpDisp)
+      return R_MIPS_GOT_GP_PC;
+    if (&S == ElfSym::MipsLocalGp)
+      return R_MIPS_GOT_GP;
+    LLVM_FALLTHROUGH;
+  case R_MIPS_GOT_OFST:
+    return R_ABS;
+  case R_MIPS_PC32:
+  case R_MIPS_PC16:
+  case R_MIPS_PC19_S2:
+  case R_MIPS_PC21_S2:
+  case R_MIPS_PC26_S2:
+  case R_MIPS_PCHI16:
+  case R_MIPS_PCLO16:
+    return R_PC;
+  case R_MIPS_GOT16:
+    if (S.isLocal())
+      return R_MIPS_GOT_LOCAL_PAGE;
+    LLVM_FALLTHROUGH;
+  case R_MIPS_CALL16:
+  case R_MIPS_GOT_DISP:
+  case R_MIPS_TLS_GOTTPREL:
+    return R_MIPS_GOT_OFF;
+  case R_MIPS_CALL_HI16:
+  case R_MIPS_CALL_LO16:
+  case R_MIPS_GOT_HI16:
+  case R_MIPS_GOT_LO16:
+    return R_MIPS_GOT_OFF32;
+  case R_MIPS_GOT_PAGE:
+    return R_MIPS_GOT_LOCAL_PAGE;
+  case R_MIPS_TLS_GD:
+    return R_MIPS_TLSGD;
+  case R_MIPS_TLS_LDM:
+    return R_MIPS_TLSLD;
+  }
+}
+
+template <class ELFT> bool MIPS<ELFT>::isPicRel(uint32_t Type) const {
+  return Type == R_MIPS_32 || Type == R_MIPS_64;
+}
+
+template <class ELFT> uint32_t MIPS<ELFT>::getDynRel(uint32_t Type) const {
+  return RelativeRel;
+}
+
+template <class ELFT>
+void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+  write32<ELFT::TargetEndianness>(Buf, InX::Plt->getVA());
+}
+
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static int64_t getPcRelocAddend(const uint8_t *Loc) {
+  uint32_t Instr = read32<E>(Loc);
+  uint32_t Mask = 0xffffffff >> (32 - BSIZE);
+  return SignExtend64<BSIZE + SHIFT>((Instr & Mask) << SHIFT);
+}
+
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) {
+  uint32_t Mask = 0xffffffff >> (32 - BSIZE);
+  uint32_t Instr = read32<E>(Loc);
+  if (SHIFT > 0)
+    checkAlignment<(1 << SHIFT)>(Loc, V, Type);
+  checkInt<BSIZE + SHIFT>(Loc, V, Type);
+  write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask));
+}
+
+template <endianness E> static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
+  uint32_t Instr = read32<E>(Loc);
+  uint16_t Res = ((V + 0x8000) >> 16) & 0xffff;
+  write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsHigher(uint8_t *Loc, uint64_t V) {
+  uint32_t Instr = read32<E>(Loc);
+  uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff;
+  write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsHighest(uint8_t *Loc, uint64_t V) {
+  uint32_t Instr = read32<E>(Loc);
+  uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff;
+  write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
+  uint32_t Instr = read32<E>(Loc);
+  write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
+}
+
+template <class ELFT> static bool isMipsR6() {
+  const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
+  uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH;
+  return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
+}
+
+template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
+  const endianness E = ELFT::TargetEndianness;
+  if (Config->MipsN32Abi) {
+    write32<E>(Buf, 0x3c0e0000);      // lui   $14, %hi(&GOTPLT[0])
+    write32<E>(Buf + 4, 0x8dd90000);  // lw    $25, %lo(&GOTPLT[0])($14)
+    write32<E>(Buf + 8, 0x25ce0000);  // addiu $14, $14, %lo(&GOTPLT[0])
+    write32<E>(Buf + 12, 0x030ec023); // subu  $24, $24, $14
+  } else {
+    write32<E>(Buf, 0x3c1c0000);      // lui   $28, %hi(&GOTPLT[0])
+    write32<E>(Buf + 4, 0x8f990000);  // lw    $25, %lo(&GOTPLT[0])($28)
+    write32<E>(Buf + 8, 0x279c0000);  // addiu $28, $28, %lo(&GOTPLT[0])
+    write32<E>(Buf + 12, 0x031cc023); // subu  $24, $24, $28
+  }
+
+  write32<E>(Buf + 16, 0x03e07825); // move  $15, $31
+  write32<E>(Buf + 20, 0x0018c082); // srl   $24, $24, 2
+  write32<E>(Buf + 24, 0x0320f809); // jalr  $25
+  write32<E>(Buf + 28, 0x2718fffe); // subu  $24, $24, 2
+
+  uint64_t GotPlt = InX::GotPlt->getVA();
+  writeMipsHi16<E>(Buf, GotPlt);
+  writeMipsLo16<E>(Buf + 4, GotPlt);
+  writeMipsLo16<E>(Buf + 8, GotPlt);
+}
+
+template <class ELFT>
+void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+                          uint64_t PltEntryAddr, int32_t Index,
+                          unsigned RelOff) const {
+  const endianness E = ELFT::TargetEndianness;
+  write32<E>(Buf, 0x3c0f0000);     // lui   $15, %hi(.got.plt entry)
+  write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
+                                   // jr    $25
+  write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
+  write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
+  writeMipsHi16<E>(Buf, GotPltEntryAddr);
+  writeMipsLo16<E>(Buf + 4, GotPltEntryAddr);
+  writeMipsLo16<E>(Buf + 12, GotPltEntryAddr);
+}
+
+template <class ELFT>
+bool MIPS<ELFT>::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File,
+                            const SymbolBody &S) const {
+  // Any MIPS PIC code function is invoked with its address in register $t9.
+  // So if we have a branch instruction from non-PIC code to the PIC one
+  // we cannot make the jump directly and need to create a small stubs
+  // to save the target function address.
+  // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (Type != R_MIPS_26)
+    return false;
+  auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
+  if (!F)
+    return false;
+  // If current file has PIC code, LA25 stub is not required.
+  if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
+    return false;
+  auto *D = dyn_cast<DefinedRegular>(&S);
+  // LA25 is required if target file has PIC code
+  // or target symbol is a PIC symbol.
+  return D && D->isMipsPIC<ELFT>();
+}
+
+template <class ELFT>
+int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
+  const endianness E = ELFT::TargetEndianness;
+  switch (Type) {
+  default:
+    return 0;
+  case R_MIPS_32:
+  case R_MIPS_GPREL32:
+  case R_MIPS_TLS_DTPREL32:
+  case R_MIPS_TLS_TPREL32:
+    return SignExtend64<32>(read32<E>(Buf));
+  case R_MIPS_26:
+    // FIXME (simon): If the relocation target symbol is not a PLT entry
+    // we should use another expression for calculation:
+    // ((A << 2) | (P & 0xf0000000)) >> 2
+    return SignExtend64<28>((read32<E>(Buf) & 0x3ffffff) << 2);
+  case R_MIPS_GPREL16:
+  case R_MIPS_LO16:
+  case R_MIPS_PCLO16:
+  case R_MIPS_TLS_DTPREL_HI16:
+  case R_MIPS_TLS_DTPREL_LO16:
+  case R_MIPS_TLS_TPREL_HI16:
+  case R_MIPS_TLS_TPREL_LO16:
+    return SignExtend64<16>(read32<E>(Buf));
+  case R_MIPS_PC16:
+    return getPcRelocAddend<E, 16, 2>(Buf);
+  case R_MIPS_PC19_S2:
+    return getPcRelocAddend<E, 19, 2>(Buf);
+  case R_MIPS_PC21_S2:
+    return getPcRelocAddend<E, 21, 2>(Buf);
+  case R_MIPS_PC26_S2:
+    return getPcRelocAddend<E, 26, 2>(Buf);
+  case R_MIPS_PC32:
+    return getPcRelocAddend<E, 32, 0>(Buf);
+  }
+}
+
+static std::pair<uint32_t, uint64_t>
+calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) {
+  // MIPS N64 ABI packs multiple relocations into the single relocation
+  // record. In general, all up to three relocations can have arbitrary
+  // types. In fact, Clang and GCC uses only a few combinations. For now,
+  // we support two of them. That is allow to pass at least all LLVM
+  // test suite cases.
+  // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
+  // <any relocation> / R_MIPS_64 / R_MIPS_NONE
+  // The first relocation is a 'real' relocation which is calculated
+  // using the corresponding symbol's value. The second and the third
+  // relocations used to modify result of the first one: extend it to
+  // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
+  // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
+  uint32_t Type2 = (Type >> 8) & 0xff;
+  uint32_t Type3 = (Type >> 16) & 0xff;
+  if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE)
+    return std::make_pair(Type, Val);
+  if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE)
+    return std::make_pair(Type2, Val);
+  if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
+    return std::make_pair(Type3, -Val);
+  error(getErrorLocation(Loc) + "unsupported relocations combination " +
+        Twine(Type));
+  return std::make_pair(Type & 0xff, Val);
+}
+
+template <class ELFT>
+void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  const endianness E = ELFT::TargetEndianness;
+  // Thread pointer and DRP offsets from the start of TLS data area.
+  // https://www.linux-mips.org/wiki/NPTL
+  if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
+      Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64)
+    Val -= 0x8000;
+  else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
+           Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
+    Val -= 0x7000;
+  if (ELFT::Is64Bits || Config->MipsN32Abi)
+    std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
+  switch (Type) {
+  case R_MIPS_32:
+  case R_MIPS_GPREL32:
+  case R_MIPS_TLS_DTPREL32:
+  case R_MIPS_TLS_TPREL32:
+    write32<E>(Loc, Val);
+    break;
+  case R_MIPS_64:
+  case R_MIPS_TLS_DTPREL64:
+  case R_MIPS_TLS_TPREL64:
+    write64<E>(Loc, Val);
+    break;
+  case R_MIPS_26:
+    write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff));
+    break;
+  case R_MIPS_GOT16:
+    // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
+    // is updated addend (not a GOT index). In that case write high 16 bits
+    // to store a correct addend value.
+    if (Config->Relocatable)
+      writeMipsHi16<E>(Loc, Val);
+    else {
+      checkInt<16>(Loc, Val, Type);
+      writeMipsLo16<E>(Loc, Val);
+    }
+    break;
+  case R_MIPS_GOT_DISP:
+  case R_MIPS_GOT_PAGE:
+  case R_MIPS_GPREL16:
+  case R_MIPS_TLS_GD:
+  case R_MIPS_TLS_LDM:
+    checkInt<16>(Loc, Val, Type);
+    LLVM_FALLTHROUGH;
+  case R_MIPS_CALL16:
+  case R_MIPS_CALL_LO16:
+  case R_MIPS_GOT_LO16:
+  case R_MIPS_GOT_OFST:
+  case R_MIPS_LO16:
+  case R_MIPS_PCLO16:
+  case R_MIPS_TLS_DTPREL_LO16:
+  case R_MIPS_TLS_GOTTPREL:
+  case R_MIPS_TLS_TPREL_LO16:
+    writeMipsLo16<E>(Loc, Val);
+    break;
+  case R_MIPS_CALL_HI16:
+  case R_MIPS_GOT_HI16:
+  case R_MIPS_HI16:
+  case R_MIPS_PCHI16:
+  case R_MIPS_TLS_DTPREL_HI16:
+  case R_MIPS_TLS_TPREL_HI16:
+    writeMipsHi16<E>(Loc, Val);
+    break;
+  case R_MIPS_HIGHER:
+    writeMipsHigher<E>(Loc, Val);
+    break;
+  case R_MIPS_HIGHEST:
+    writeMipsHighest<E>(Loc, Val);
+    break;
+  case R_MIPS_JALR:
+    // Ignore this optimization relocation for now
+    break;
+  case R_MIPS_PC16:
+    applyMipsPcReloc<E, 16, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC19_S2:
+    applyMipsPcReloc<E, 19, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC21_S2:
+    applyMipsPcReloc<E, 21, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC26_S2:
+    applyMipsPcReloc<E, 26, 2>(Loc, Type, Val);
+    break;
+  case R_MIPS_PC32:
+    applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+template <class ELFT>
+bool MIPS<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
+  return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
+}
+
+template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
+  static MIPS<ELFT> Target;
+  return &Target;
+}
+
+template TargetInfo *elf::getMipsTargetInfo<ELF32LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF32BE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64BE>();
diff --git a/ELF/Arch/MipsArchTree.cpp b/ELF/Arch/MipsArchTree.cpp
new file mode 100644 (file)
index 0000000..3d1dc1d
--- /dev/null
@@ -0,0 +1,369 @@
+//===- MipsArchTree.cpp --------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file contains a helper function for the Writer.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Writer.h"
+
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/MipsABIFlags.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+struct ArchTreeEdge {
+  uint32_t Child;
+  uint32_t Parent;
+};
+
+struct FileFlags {
+  StringRef Filename;
+  uint32_t Flags;
+};
+} // namespace
+
+static StringRef getAbiName(uint32_t Flags) {
+  switch (Flags) {
+  case 0:
+    return "n64";
+  case EF_MIPS_ABI2:
+    return "n32";
+  case EF_MIPS_ABI_O32:
+    return "o32";
+  case EF_MIPS_ABI_O64:
+    return "o64";
+  case EF_MIPS_ABI_EABI32:
+    return "eabi32";
+  case EF_MIPS_ABI_EABI64:
+    return "eabi64";
+  default:
+    return "unknown";
+  }
+}
+
+static StringRef getNanName(bool IsNan2008) {
+  return IsNan2008 ? "2008" : "legacy";
+}
+
+static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; }
+
+static void checkFlags(ArrayRef<FileFlags> Files) {
+  uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
+  bool Nan = Files[0].Flags & EF_MIPS_NAN2008;
+  bool Fp = Files[0].Flags & EF_MIPS_FP64;
+
+  for (const FileFlags &F : Files.slice(1)) {
+    uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
+    if (ABI != ABI2)
+      error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" +
+            getAbiName(ABI2) + "': " + F.Filename);
+
+    bool Nan2 = F.Flags & EF_MIPS_NAN2008;
+    if (Nan != Nan2)
+      error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" +
+            getNanName(Nan2) + ": " + F.Filename);
+
+    bool Fp2 = F.Flags & EF_MIPS_FP64;
+    if (Fp != Fp2)
+      error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" +
+            getFpName(Fp2) + ": " + F.Filename);
+  }
+}
+
+static uint32_t getMiscFlags(ArrayRef<FileFlags> Files) {
+  uint32_t Ret = 0;
+  for (const FileFlags &F : Files)
+    Ret |= F.Flags &
+           (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER |
+            EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE);
+  return Ret;
+}
+
+static uint32_t getPicFlags(ArrayRef<FileFlags> Files) {
+  // Check PIC/non-PIC compatibility.
+  bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+  for (const FileFlags &F : Files.slice(1)) {
+    bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+    if (IsPic && !IsPic2)
+      warn("linking abicalls code with non-abicalls file: " + F.Filename);
+    if (!IsPic && IsPic2)
+      warn("linking non-abicalls code with abicalls file: " + F.Filename);
+  }
+
+  // Compute the result PIC/non-PIC flag.
+  uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+  for (const FileFlags &F : Files.slice(1))
+    Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+
+  // PIC code is inherently CPIC and may not set CPIC flag explicitly.
+  if (Ret & EF_MIPS_PIC)
+    Ret |= EF_MIPS_CPIC;
+  return Ret;
+}
+
+static ArchTreeEdge ArchTree[] = {
+    // MIPS32R6 and MIPS64R6 are not compatible with other extensions
+    // MIPS64R2 extensions.
+    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},
+    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},
+    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},
+    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},
+    // MIPS64 extensions.
+    {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},
+    {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},
+    {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
+    // MIPS V extensions.
+    {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
+    // R5000 extensions.
+    {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},
+    // MIPS IV extensions.
+    {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},
+    {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},
+    {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
+    // VR4100 extensions.
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
+    // MIPS III extensions.
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},
+    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},
+    {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
+    // MIPS32 extensions.
+    {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
+    // MIPS II extensions.
+    {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
+    {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
+    // MIPS I extensions.
+    {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},
+    {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
+};
+
+static bool isArchMatched(uint32_t New, uint32_t Res) {
+  if (New == Res)
+    return true;
+  if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res))
+    return true;
+  if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res))
+    return true;
+  for (const auto &Edge : ArchTree) {
+    if (Res == Edge.Child) {
+      Res = Edge.Parent;
+      if (Res == New)
+        return true;
+    }
+  }
+  return false;
+}
+
+static StringRef getMachName(uint32_t Flags) {
+  switch (Flags & EF_MIPS_MACH) {
+  case EF_MIPS_MACH_NONE:
+    return "";
+  case EF_MIPS_MACH_3900:
+    return "r3900";
+  case EF_MIPS_MACH_4010:
+    return "r4010";
+  case EF_MIPS_MACH_4100:
+    return "r4100";
+  case EF_MIPS_MACH_4650:
+    return "r4650";
+  case EF_MIPS_MACH_4120:
+    return "r4120";
+  case EF_MIPS_MACH_4111:
+    return "r4111";
+  case EF_MIPS_MACH_5400:
+    return "vr5400";
+  case EF_MIPS_MACH_5900:
+    return "vr5900";
+  case EF_MIPS_MACH_5500:
+    return "vr5500";
+  case EF_MIPS_MACH_9000:
+    return "rm9000";
+  case EF_MIPS_MACH_LS2E:
+    return "loongson2e";
+  case EF_MIPS_MACH_LS2F:
+    return "loongson2f";
+  case EF_MIPS_MACH_LS3A:
+    return "loongson3a";
+  case EF_MIPS_MACH_OCTEON:
+    return "octeon";
+  case EF_MIPS_MACH_OCTEON2:
+    return "octeon2";
+  case EF_MIPS_MACH_OCTEON3:
+    return "octeon3";
+  case EF_MIPS_MACH_SB1:
+    return "sb1";
+  case EF_MIPS_MACH_XLR:
+    return "xlr";
+  default:
+    return "unknown machine";
+  }
+}
+
+static StringRef getArchName(uint32_t Flags) {
+  StringRef S = getMachName(Flags);
+  if (!S.empty())
+    return S;
+
+  switch (Flags & EF_MIPS_ARCH) {
+  case EF_MIPS_ARCH_1:
+    return "mips1";
+  case EF_MIPS_ARCH_2:
+    return "mips2";
+  case EF_MIPS_ARCH_3:
+    return "mips3";
+  case EF_MIPS_ARCH_4:
+    return "mips4";
+  case EF_MIPS_ARCH_5:
+    return "mips5";
+  case EF_MIPS_ARCH_32:
+    return "mips32";
+  case EF_MIPS_ARCH_64:
+    return "mips64";
+  case EF_MIPS_ARCH_32R2:
+    return "mips32r2";
+  case EF_MIPS_ARCH_64R2:
+    return "mips64r2";
+  case EF_MIPS_ARCH_32R6:
+    return "mips32r6";
+  case EF_MIPS_ARCH_64R6:
+    return "mips64r6";
+  default:
+    return "unknown arch";
+  }
+}
+
+// There are (arguably too) many MIPS ISAs out there. Their relationships
+// can be represented as a forest. If all input files have ISAs which
+// reachable by repeated proceeding from the single child to the parent,
+// these input files are compatible. In that case we need to return "highest"
+// ISA. If there are incompatible input files, we show an error.
+// For example, mips1 is a "parent" of mips2 and such files are compatible.
+// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32
+// are incompatible because nor mips3 is a parent for misp32, nor mips32
+// is a parent for mips3.
+static uint32_t getArchFlags(ArrayRef<FileFlags> Files) {
+  uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+
+  for (const FileFlags &F : Files.slice(1)) {
+    uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+
+    // Check ISA compatibility.
+    if (isArchMatched(New, Ret))
+      continue;
+    if (!isArchMatched(Ret, New)) {
+      error("target ISA '" + getArchName(Ret) + "' is incompatible with '" +
+            getArchName(New) + "': " + F.Filename);
+      return 0;
+    }
+    Ret = New;
+  }
+  return Ret;
+}
+
+template <class ELFT> uint32_t elf::getMipsEFlags() {
+  std::vector<FileFlags> V;
+  for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles())
+    V.push_back({F->getName(), F->getObj().getHeader()->e_flags});
+  if (V.empty())
+    return 0;
+  checkFlags(V);
+  return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V);
+}
+
+static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) {
+  if (FpA == FpB)
+    return 0;
+  if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY)
+    return 1;
+  if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A &&
+      FpA == Mips::Val_GNU_MIPS_ABI_FP_64)
+    return 1;
+  if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX)
+    return -1;
+  if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
+      FpA == Mips::Val_GNU_MIPS_ABI_FP_64 ||
+      FpA == Mips::Val_GNU_MIPS_ABI_FP_64A)
+    return 1;
+  return -1;
+}
+
+static StringRef getMipsFpAbiName(uint8_t FpAbi) {
+  switch (FpAbi) {
+  case Mips::Val_GNU_MIPS_ABI_FP_ANY:
+    return "any";
+  case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
+    return "-mdouble-float";
+  case Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
+    return "-msingle-float";
+  case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
+    return "-msoft-float";
+  case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
+    return "-mips32r2 -mfp64 (old)";
+  case Mips::Val_GNU_MIPS_ABI_FP_XX:
+    return "-mfpxx";
+  case Mips::Val_GNU_MIPS_ABI_FP_64:
+    return "-mgp32 -mfp64";
+  case Mips::Val_GNU_MIPS_ABI_FP_64A:
+    return "-mgp32 -mfp64 -mno-odd-spreg";
+  default:
+    return "unknown";
+  }
+}
+
+uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
+                              StringRef FileName) {
+  if (compareMipsFpAbi(NewFlag, OldFlag) >= 0)
+    return NewFlag;
+  if (compareMipsFpAbi(OldFlag, NewFlag) < 0)
+    error("target floating point ABI '" + getMipsFpAbiName(OldFlag) +
+          "' is incompatible with '" + getMipsFpAbiName(NewFlag) +
+          "': " + FileName);
+  return OldFlag;
+}
+
+template <class ELFT> static bool isN32Abi(const InputFile *F) {
+  if (auto *EF = dyn_cast<ELFFileBase<ELFT>>(F))
+    return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2;
+  return false;
+}
+
+bool elf::isMipsN32Abi(const InputFile *F) {
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    return isN32Abi<ELF32LE>(F);
+  case ELF32BEKind:
+    return isN32Abi<ELF32BE>(F);
+  case ELF64LEKind:
+    return isN32Abi<ELF64LE>(F);
+  case ELF64BEKind:
+    return isN32Abi<ELF64BE>(F);
+  default:
+    llvm_unreachable("unknown Config->EKind");
+  }
+}
+
+template uint32_t elf::getMipsEFlags<ELF32LE>();
+template uint32_t elf::getMipsEFlags<ELF32BE>();
+template uint32_t elf::getMipsEFlags<ELF64LE>();
+template uint32_t elf::getMipsEFlags<ELF64BE>();
diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp
new file mode 100644 (file)
index 0000000..19e1072
--- /dev/null
@@ -0,0 +1,65 @@
+//===- PPC.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class PPC final : public TargetInfo {
+public:
+  PPC() { GotBaseSymOff = 0x8000; }
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+};
+} // namespace
+
+void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  switch (Type) {
+  case R_PPC_ADDR16_HA:
+    write16be(Loc, (Val + 0x8000) >> 16);
+    break;
+  case R_PPC_ADDR16_LO:
+    write16be(Loc, Val);
+    break;
+  case R_PPC_ADDR32:
+  case R_PPC_REL32:
+    write32be(Loc, Val);
+    break;
+  case R_PPC_REL24:
+    write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC));
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S,
+                        const uint8_t *Loc) const {
+  switch (Type) {
+  case R_PPC_REL24:
+  case R_PPC_REL32:
+    return R_PC;
+  default:
+    return R_ABS;
+  }
+}
+
+TargetInfo *elf::getPPCTargetInfo() {
+  static PPC Target;
+  return &Target;
+}
diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp
new file mode 100644 (file)
index 0000000..bf414d7
--- /dev/null
@@ -0,0 +1,217 @@
+//===- PPC64.cpp ----------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+static uint64_t PPC64TocOffset = 0x8000;
+
+uint64_t elf::getPPC64TocBase() {
+  // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
+  // TOC starts where the first of these sections starts. We always create a
+  // .got when we see a relocation that uses it, so for us the start is always
+  // the .got.
+  uint64_t TocVA = InX::Got->getVA();
+
+  // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
+  // thus permitting a full 64 Kbytes segment. Note that the glibc startup
+  // code (crt1.o) assumes that you can get from the TOC base to the
+  // start of the .toc section with only a single (signed) 16-bit relocation.
+  return TocVA + PPC64TocOffset;
+}
+
+namespace {
+class PPC64 final : public TargetInfo {
+public:
+  PPC64();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+// Relocation masks following the #lo(value), #hi(value), #ha(value),
+// #higher(value), #highera(value), #highest(value), and #highesta(value)
+// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
+// document.
+static uint16_t applyPPCLo(uint64_t V) { return V; }
+static uint16_t applyPPCHi(uint64_t V) { return V >> 16; }
+static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; }
+static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; }
+static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
+static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
+static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
+
+PPC64::PPC64() {
+  PltRel = GotRel = R_PPC64_GLOB_DAT;
+  RelativeRel = R_PPC64_RELATIVE;
+  GotEntrySize = 8;
+  GotPltEntrySize = 8;
+  PltEntrySize = 32;
+  PltHeaderSize = 0;
+
+  // We need 64K pages (at least under glibc/Linux, the loader won't
+  // set different permissions on a finer granularity than that).
+  DefaultMaxPageSize = 65536;
+
+  // The PPC64 ELF ABI v1 spec, says:
+  //
+  //   It is normally desirable to put segments with different characteristics
+  //   in separate 256 Mbyte portions of the address space, to give the
+  //   operating system full paging flexibility in the 64-bit address space.
+  //
+  // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
+  // use 0x10000000 as the starting address.
+  DefaultImageBase = 0x10000000;
+}
+
+RelExpr PPC64::getRelExpr(uint32_t Type, const SymbolBody &S,
+                          const uint8_t *Loc) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_PPC64_TOC16:
+  case R_PPC64_TOC16_DS:
+  case R_PPC64_TOC16_HA:
+  case R_PPC64_TOC16_HI:
+  case R_PPC64_TOC16_LO:
+  case R_PPC64_TOC16_LO_DS:
+    return R_GOTREL;
+  case R_PPC64_TOC:
+    return R_PPC_TOC;
+  case R_PPC64_REL24:
+    return R_PPC_PLT_OPD;
+  }
+}
+
+void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+                     uint64_t PltEntryAddr, int32_t Index,
+                     unsigned RelOff) const {
+  uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
+
+  // FIXME: What we should do, in theory, is get the offset of the function
+  // descriptor in the .opd section, and use that as the offset from %r2 (the
+  // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
+  // be a pointer to the function descriptor in the .opd section. Using
+  // this scheme is simpler, but requires an extra indirection per PLT dispatch.
+
+  write32be(Buf, 0xf8410028);                       // std %r2, 40(%r1)
+  write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
+  write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
+  write32be(Buf + 12, 0xe96c0000);                  // ld %r11,0(%r12)
+  write32be(Buf + 16, 0x7d6903a6);                  // mtctr %r11
+  write32be(Buf + 20, 0xe84c0008);                  // ld %r2,8(%r12)
+  write32be(Buf + 24, 0xe96c0010);                  // ld %r11,16(%r12)
+  write32be(Buf + 28, 0x4e800420);                  // bctr
+}
+
+static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) {
+  uint64_t V = Val - PPC64TocOffset;
+  switch (Type) {
+  case R_PPC64_TOC16:
+    return {R_PPC64_ADDR16, V};
+  case R_PPC64_TOC16_DS:
+    return {R_PPC64_ADDR16_DS, V};
+  case R_PPC64_TOC16_HA:
+    return {R_PPC64_ADDR16_HA, V};
+  case R_PPC64_TOC16_HI:
+    return {R_PPC64_ADDR16_HI, V};
+  case R_PPC64_TOC16_LO:
+    return {R_PPC64_ADDR16_LO, V};
+  case R_PPC64_TOC16_LO_DS:
+    return {R_PPC64_ADDR16_LO_DS, V};
+  default:
+    return {Type, Val};
+  }
+}
+
+void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  // For a TOC-relative relocation, proceed in terms of the corresponding
+  // ADDR16 relocation type.
+  std::tie(Type, Val) = toAddr16Rel(Type, Val);
+
+  switch (Type) {
+  case R_PPC64_ADDR14: {
+    checkAlignment<4>(Loc, Val, Type);
+    // Preserve the AA/LK bits in the branch instruction
+    uint8_t AALK = Loc[3];
+    write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
+    break;
+  }
+  case R_PPC64_ADDR16:
+    checkInt<16>(Loc, Val, Type);
+    write16be(Loc, Val);
+    break;
+  case R_PPC64_ADDR16_DS:
+    checkInt<16>(Loc, Val, Type);
+    write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
+    break;
+  case R_PPC64_ADDR16_HA:
+  case R_PPC64_REL16_HA:
+    write16be(Loc, applyPPCHa(Val));
+    break;
+  case R_PPC64_ADDR16_HI:
+  case R_PPC64_REL16_HI:
+    write16be(Loc, applyPPCHi(Val));
+    break;
+  case R_PPC64_ADDR16_HIGHER:
+    write16be(Loc, applyPPCHigher(Val));
+    break;
+  case R_PPC64_ADDR16_HIGHERA:
+    write16be(Loc, applyPPCHighera(Val));
+    break;
+  case R_PPC64_ADDR16_HIGHEST:
+    write16be(Loc, applyPPCHighest(Val));
+    break;
+  case R_PPC64_ADDR16_HIGHESTA:
+    write16be(Loc, applyPPCHighesta(Val));
+    break;
+  case R_PPC64_ADDR16_LO:
+    write16be(Loc, applyPPCLo(Val));
+    break;
+  case R_PPC64_ADDR16_LO_DS:
+  case R_PPC64_REL16_LO:
+    write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
+    break;
+  case R_PPC64_ADDR32:
+  case R_PPC64_REL32:
+    checkInt<32>(Loc, Val, Type);
+    write32be(Loc, Val);
+    break;
+  case R_PPC64_ADDR64:
+  case R_PPC64_REL64:
+  case R_PPC64_TOC:
+    write64be(Loc, Val);
+    break;
+  case R_PPC64_REL24: {
+    uint32_t Mask = 0x03FFFFFC;
+    checkInt<24>(Loc, Val, Type);
+    write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
+    break;
+  }
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+TargetInfo *elf::getPPC64TargetInfo() {
+  static PPC64 Target;
+  return &Target;
+}
diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp
new file mode 100644 (file)
index 0000000..1f977c1
--- /dev/null
@@ -0,0 +1,149 @@
+//===- SPARCV9.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class SPARCV9 final : public TargetInfo {
+public:
+  SPARCV9();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+SPARCV9::SPARCV9() {
+  CopyRel = R_SPARC_COPY;
+  GotRel = R_SPARC_GLOB_DAT;
+  PltRel = R_SPARC_JMP_SLOT;
+  RelativeRel = R_SPARC_RELATIVE;
+  GotEntrySize = 8;
+  PltEntrySize = 32;
+  PltHeaderSize = 4 * PltEntrySize;
+
+  PageSize = 8192;
+  DefaultMaxPageSize = 0x100000;
+  DefaultImageBase = 0x100000;
+}
+
+RelExpr SPARCV9::getRelExpr(uint32_t Type, const SymbolBody &S,
+                            const uint8_t *Loc) const {
+  switch (Type) {
+  case R_SPARC_32:
+  case R_SPARC_UA32:
+  case R_SPARC_64:
+  case R_SPARC_UA64:
+    return R_ABS;
+  case R_SPARC_PC10:
+  case R_SPARC_PC22:
+  case R_SPARC_DISP32:
+  case R_SPARC_WDISP30:
+    return R_PC;
+  case R_SPARC_GOT10:
+    return R_GOT_OFF;
+  case R_SPARC_GOT22:
+    return R_GOT_OFF;
+  case R_SPARC_WPLT30:
+    return R_PLT_PC;
+  case R_SPARC_NONE:
+    return R_NONE;
+  default:
+    error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+    return R_HINT;
+  }
+}
+
+void SPARCV9::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  switch (Type) {
+  case R_SPARC_32:
+  case R_SPARC_UA32:
+    // V-word32
+    checkUInt<32>(Loc, Val, Type);
+    write32be(Loc, Val);
+    break;
+  case R_SPARC_DISP32:
+    // V-disp32
+    checkInt<32>(Loc, Val, Type);
+    write32be(Loc, Val);
+    break;
+  case R_SPARC_WDISP30:
+  case R_SPARC_WPLT30:
+    // V-disp30
+    checkInt<32>(Loc, Val, Type);
+    write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff));
+    break;
+  case R_SPARC_22:
+    // V-imm22
+    checkUInt<22>(Loc, Val, Type);
+    write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff));
+    break;
+  case R_SPARC_GOT22:
+  case R_SPARC_PC22:
+    // T-imm22
+    write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff));
+    break;
+  case R_SPARC_WDISP19:
+    // V-disp19
+    checkInt<21>(Loc, Val, Type);
+    write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff));
+    break;
+  case R_SPARC_GOT10:
+  case R_SPARC_PC10:
+    // T-simm10
+    write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff));
+    break;
+  case R_SPARC_64:
+  case R_SPARC_UA64:
+  case R_SPARC_GLOB_DAT:
+    // V-xword64
+    write64be(Loc, Val);
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+  }
+}
+
+void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                       uint64_t PltEntryAddr, int32_t Index,
+                       unsigned RelOff) const {
+  const uint8_t PltData[] = {
+      0x03, 0x00, 0x00, 0x00, // sethi   (. - .PLT0), %g1
+      0x30, 0x68, 0x00, 0x00, // ba,a    %xcc, .PLT1
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00, // nop
+      0x01, 0x00, 0x00, 0x00  // nop
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+
+  uint64_t Off = PltHeaderSize + Index * PltEntrySize;
+  relocateOne(Buf, R_SPARC_22, Off);
+  relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize));
+}
+
+TargetInfo *elf::getSPARCV9TargetInfo() {
+  static SPARCV9 Target;
+  return &Target;
+}
diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp
new file mode 100644 (file)
index 0000000..a1e9bca
--- /dev/null
@@ -0,0 +1,364 @@
+//===- X86.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class X86 final : public TargetInfo {
+public:
+  X86();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+  void writeGotPltHeader(uint8_t *Buf) const override;
+  uint32_t getDynRel(uint32_t Type) const override;
+  void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+  void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+  void writePltHeader(uint8_t *Buf) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+  RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                          RelExpr Expr) const override;
+  void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+X86::X86() {
+  GotBaseSymOff = -1;
+  CopyRel = R_386_COPY;
+  GotRel = R_386_GLOB_DAT;
+  PltRel = R_386_JUMP_SLOT;
+  IRelativeRel = R_386_IRELATIVE;
+  RelativeRel = R_386_RELATIVE;
+  TlsGotRel = R_386_TLS_TPOFF;
+  TlsModuleIndexRel = R_386_TLS_DTPMOD32;
+  TlsOffsetRel = R_386_TLS_DTPOFF32;
+  GotEntrySize = 4;
+  GotPltEntrySize = 4;
+  PltEntrySize = 16;
+  PltHeaderSize = 16;
+  TlsGdRelaxSkip = 2;
+  TrapInstr = 0xcccccccc; // 0xcc = INT3
+}
+
+RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S,
+                        const uint8_t *Loc) const {
+  switch (Type) {
+  case R_386_8:
+  case R_386_16:
+  case R_386_32:
+  case R_386_TLS_LDO_32:
+    return R_ABS;
+  case R_386_TLS_GD:
+    return R_TLSGD;
+  case R_386_TLS_LDM:
+    return R_TLSLD;
+  case R_386_PLT32:
+    return R_PLT_PC;
+  case R_386_PC8:
+  case R_386_PC16:
+  case R_386_PC32:
+    return R_PC;
+  case R_386_GOTPC:
+    return R_GOTONLY_PC_FROM_END;
+  case R_386_TLS_IE:
+    return R_GOT;
+  case R_386_GOT32:
+  case R_386_GOT32X:
+    // These relocations can be calculated in two different ways.
+    // Usual calculation is G + A - GOT what means an offset in GOT table
+    // (R_GOT_FROM_END). When instruction pointed by relocation has no base
+    // register, then relocations can be used when PIC code is disabled. In that
+    // case calculation is G + A, it resolves to an address of entry in GOT
+    // (R_GOT) and not an offset.
+    //
+    // To check that instruction has no base register we scan ModR/M byte.
+    // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte"
+    // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
+    //  64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
+    if ((Loc[-1] & 0xc7) != 0x5)
+      return R_GOT_FROM_END;
+    if (Config->Pic)
+      error(toString(S.File) + ": relocation " + toString(Type) + " against '" +
+            S.getName() +
+            "' without base register can not be used when PIC enabled");
+    return R_GOT;
+  case R_386_TLS_GOTIE:
+    return R_GOT_FROM_END;
+  case R_386_GOTOFF:
+    return R_GOTREL_FROM_END;
+  case R_386_TLS_LE:
+    return R_TLS;
+  case R_386_TLS_LE_32:
+    return R_NEG_TLS;
+  case R_386_NONE:
+    return R_NONE;
+  default:
+    error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+    return R_HINT;
+  }
+}
+
+RelExpr X86::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                             RelExpr Expr) const {
+  switch (Expr) {
+  default:
+    return Expr;
+  case R_RELAX_TLS_GD_TO_IE:
+    return R_RELAX_TLS_GD_TO_IE_END;
+  case R_RELAX_TLS_GD_TO_LE:
+    return R_RELAX_TLS_GD_TO_LE_NEG;
+  }
+}
+
+void X86::writeGotPltHeader(uint8_t *Buf) const {
+  write32le(Buf, InX::Dynamic->getVA());
+}
+
+void X86::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
+  // Entries in .got.plt initially points back to the corresponding
+  // PLT entries with a fixed offset to skip the first instruction.
+  write32le(Buf, S.getPltVA() + 6);
+}
+
+void X86::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+  // An x86 entry is the address of the ifunc resolver function.
+  write32le(Buf, S.getVA());
+}
+
+uint32_t X86::getDynRel(uint32_t Type) const {
+  if (Type == R_386_TLS_LE)
+    return R_386_TLS_TPOFF;
+  if (Type == R_386_TLS_LE_32)
+    return R_386_TLS_TPOFF32;
+  return Type;
+}
+
+void X86::writePltHeader(uint8_t *Buf) const {
+  if (Config->Pic) {
+    const uint8_t V[] = {
+        0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx)
+        0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx)
+        0x90, 0x90, 0x90, 0x90              // nop
+    };
+    memcpy(Buf, V, sizeof(V));
+
+    uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+    uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
+    write32le(Buf + 2, GotPlt + 4);
+    write32le(Buf + 8, GotPlt + 8);
+    return;
+  }
+
+  const uint8_t PltData[] = {
+      0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4)
+      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8)
+      0x90, 0x90, 0x90, 0x90              // nop
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+  uint32_t GotPlt = InX::GotPlt->getVA();
+  write32le(Buf + 2, GotPlt + 4);
+  write32le(Buf + 8, GotPlt + 8);
+}
+
+void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+                   uint64_t PltEntryAddr, int32_t Index,
+                   unsigned RelOff) const {
+  const uint8_t Inst[] = {
+      0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx)
+      0x68, 0x00, 0x00, 0x00, 0x00,       // pushl $reloc_offset
+      0xe9, 0x00, 0x00, 0x00, 0x00        // jmp .PLT0@PC
+  };
+  memcpy(Buf, Inst, sizeof(Inst));
+
+  if (Config->Pic) {
+    // jmp *foo@GOT(%ebx)
+    uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+    Buf[1] = 0xa3;
+    write32le(Buf + 2, GotPltEntryAddr - Ebx);
+  } else {
+    // jmp *foo_in_GOT
+    Buf[1] = 0x25;
+    write32le(Buf + 2, GotPltEntryAddr);
+  }
+
+  write32le(Buf + 7, RelOff);
+  write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+}
+
+int64_t X86::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
+  switch (Type) {
+  default:
+    return 0;
+  case R_386_8:
+  case R_386_PC8:
+    return SignExtend64<8>(*Buf);
+  case R_386_16:
+  case R_386_PC16:
+    return SignExtend64<16>(read16le(Buf));
+  case R_386_32:
+  case R_386_GOT32:
+  case R_386_GOT32X:
+  case R_386_GOTOFF:
+  case R_386_GOTPC:
+  case R_386_PC32:
+  case R_386_PLT32:
+  case R_386_TLS_LDO_32:
+  case R_386_TLS_LE:
+    return SignExtend64<32>(read32le(Buf));
+  }
+}
+
+void X86::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
+  // being used for some 16-bit programs such as boot loaders, so
+  // we want to support them.
+  switch (Type) {
+  case R_386_8:
+    checkUInt<8>(Loc, Val, Type);
+    *Loc = Val;
+    break;
+  case R_386_PC8:
+    checkInt<8>(Loc, Val, Type);
+    *Loc = Val;
+    break;
+  case R_386_16:
+    checkUInt<16>(Loc, Val, Type);
+    write16le(Loc, Val);
+    break;
+  case R_386_PC16:
+    // R_386_PC16 is normally used with 16 bit code. In that situation
+    // the PC is 16 bits, just like the addend. This means that it can
+    // point from any 16 bit address to any other if the possibility
+    // of wrapping is included.
+    // The only restriction we have to check then is that the destination
+    // address fits in 16 bits. That is impossible to do here. The problem is
+    // that we are passed the final value, which already had the
+    // current location subtracted from it.
+    // We just check that Val fits in 17 bits. This misses some cases, but
+    // should have no false positives.
+    checkInt<17>(Loc, Val, Type);
+    write16le(Loc, Val);
+    break;
+  default:
+    checkInt<32>(Loc, Val, Type);
+    write32le(Loc, Val);
+  }
+}
+
+void X86::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  // Convert
+  //   leal x@tlsgd(, %ebx, 1),
+  //   call __tls_get_addr@plt
+  // to
+  //   movl %gs:0,%eax
+  //   subl $x@ntpoff,%eax
+  const uint8_t Inst[] = {
+      0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
+      0x81, 0xe8, 0x00, 0x00, 0x00, 0x00  // subl 0(%ebx), %eax
+  };
+  memcpy(Loc - 3, Inst, sizeof(Inst));
+  write32le(Loc + 5, Val);
+}
+
+void X86::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  // Convert
+  //   leal x@tlsgd(, %ebx, 1),
+  //   call __tls_get_addr@plt
+  // to
+  //   movl %gs:0, %eax
+  //   addl x@gotntpoff(%ebx), %eax
+  const uint8_t Inst[] = {
+      0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
+      0x03, 0x83, 0x00, 0x00, 0x00, 0x00  // addl 0(%ebx), %eax
+  };
+  memcpy(Loc - 3, Inst, sizeof(Inst));
+  write32le(Loc + 5, Val);
+}
+
+// In some conditions, relocations can be optimized to avoid using GOT.
+// This function does that for Initial Exec to Local Exec case.
+void X86::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  // Ulrich's document section 6.2 says that @gotntpoff can
+  // be used with MOVL or ADDL instructions.
+  // @indntpoff is similar to @gotntpoff, but for use in
+  // position dependent code.
+  uint8_t Reg = (Loc[-1] >> 3) & 7;
+
+  if (Type == R_386_TLS_IE) {
+    if (Loc[-1] == 0xa1) {
+      // "movl foo@indntpoff,%eax" -> "movl $foo,%eax"
+      // This case is different from the generic case below because
+      // this is a 5 byte instruction while below is 6 bytes.
+      Loc[-1] = 0xb8;
+    } else if (Loc[-2] == 0x8b) {
+      // "movl foo@indntpoff,%reg" -> "movl $foo,%reg"
+      Loc[-2] = 0xc7;
+      Loc[-1] = 0xc0 | Reg;
+    } else {
+      // "addl foo@indntpoff,%reg" -> "addl $foo,%reg"
+      Loc[-2] = 0x81;
+      Loc[-1] = 0xc0 | Reg;
+    }
+  } else {
+    assert(Type == R_386_TLS_GOTIE);
+    if (Loc[-2] == 0x8b) {
+      // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"
+      Loc[-2] = 0xc7;
+      Loc[-1] = 0xc0 | Reg;
+    } else {
+      // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"
+      Loc[-2] = 0x8d;
+      Loc[-1] = 0x80 | (Reg << 3) | Reg;
+    }
+  }
+  write32le(Loc, Val);
+}
+
+void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  if (Type == R_386_TLS_LDO_32) {
+    write32le(Loc, Val);
+    return;
+  }
+
+  // Convert
+  //   leal foo(%reg),%eax
+  //   call ___tls_get_addr
+  // to
+  //   movl %gs:0,%eax
+  //   nop
+  //   leal 0(%esi,1),%esi
+  const uint8_t Inst[] = {
+      0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
+      0x90,                               // nop
+      0x8d, 0x74, 0x26, 0x00              // leal 0(%esi,1),%esi
+  };
+  memcpy(Loc - 2, Inst, sizeof(Inst));
+}
+
+TargetInfo *elf::getX86TargetInfo() {
+  static X86 Target;
+  return &Target;
+}
diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp
new file mode 100644 (file)
index 0000000..10179f5
--- /dev/null
@@ -0,0 +1,473 @@
+//===- X86_64.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+template <class ELFT> class X86_64 final : public TargetInfo {
+public:
+  X86_64();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                     const uint8_t *Loc) const override;
+  bool isPicRel(uint32_t Type) const override;
+  void writeGotPltHeader(uint8_t *Buf) const override;
+  void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+  void writePltHeader(uint8_t *Buf) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+  RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                          RelExpr Expr) const override;
+  void relaxGot(uint8_t *Loc, uint64_t Val) const override;
+  void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+private:
+  void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
+                     uint8_t ModRm) const;
+};
+} // namespace
+
+template <class ELFT> X86_64<ELFT>::X86_64() {
+  GotBaseSymOff = -1;
+  CopyRel = R_X86_64_COPY;
+  GotRel = R_X86_64_GLOB_DAT;
+  PltRel = R_X86_64_JUMP_SLOT;
+  RelativeRel = R_X86_64_RELATIVE;
+  IRelativeRel = R_X86_64_IRELATIVE;
+  TlsGotRel = R_X86_64_TPOFF64;
+  TlsModuleIndexRel = R_X86_64_DTPMOD64;
+  TlsOffsetRel = R_X86_64_DTPOFF64;
+  GotEntrySize = 8;
+  GotPltEntrySize = 8;
+  PltEntrySize = 16;
+  PltHeaderSize = 16;
+  TlsGdRelaxSkip = 2;
+  TrapInstr = 0xcccccccc; // 0xcc = INT3
+
+  // Align to the large page size (known as a superpage or huge page).
+  // FreeBSD automatically promotes large, superpage-aligned allocations.
+  DefaultImageBase = 0x200000;
+}
+
+template <class ELFT>
+RelExpr X86_64<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
+                                 const uint8_t *Loc) const {
+  switch (Type) {
+  case R_X86_64_8:
+  case R_X86_64_16:
+  case R_X86_64_32:
+  case R_X86_64_32S:
+  case R_X86_64_64:
+  case R_X86_64_DTPOFF32:
+  case R_X86_64_DTPOFF64:
+    return R_ABS;
+  case R_X86_64_TPOFF32:
+    return R_TLS;
+  case R_X86_64_TLSLD:
+    return R_TLSLD_PC;
+  case R_X86_64_TLSGD:
+    return R_TLSGD_PC;
+  case R_X86_64_SIZE32:
+  case R_X86_64_SIZE64:
+    return R_SIZE;
+  case R_X86_64_PLT32:
+    return R_PLT_PC;
+  case R_X86_64_PC32:
+  case R_X86_64_PC64:
+    return R_PC;
+  case R_X86_64_GOT32:
+  case R_X86_64_GOT64:
+    return R_GOT_FROM_END;
+  case R_X86_64_GOTPCREL:
+  case R_X86_64_GOTPCRELX:
+  case R_X86_64_REX_GOTPCRELX:
+  case R_X86_64_GOTTPOFF:
+    return R_GOT_PC;
+  case R_X86_64_NONE:
+    return R_NONE;
+  default:
+    error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+    return R_HINT;
+  }
+}
+
+template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
+  // The first entry holds the value of _DYNAMIC. It is not clear why that is
+  // required, but it is documented in the psabi and the glibc dynamic linker
+  // seems to use it (note that this is relevant for linking ld.so, not any
+  // other program).
+  write64le(Buf, InX::Dynamic->getVA());
+}
+
+template <class ELFT>
+void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
+  // See comments in X86TargetInfo::writeGotPlt.
+  write32le(Buf, S.getPltVA() + 6);
+}
+
+template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
+  const uint8_t PltData[] = {
+      0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip)
+      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip)
+      0x0f, 0x1f, 0x40, 0x00              // nop
+  };
+  memcpy(Buf, PltData, sizeof(PltData));
+  uint64_t GotPlt = InX::GotPlt->getVA();
+  uint64_t Plt = InX::Plt->getVA();
+  write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
+  write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
+}
+
+template <class ELFT>
+void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+                            uint64_t PltEntryAddr, int32_t Index,
+                            unsigned RelOff) const {
+  const uint8_t Inst[] = {
+      0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
+      0x68, 0x00, 0x00, 0x00, 0x00,       // pushq <relocation index>
+      0xe9, 0x00, 0x00, 0x00, 0x00        // jmpq plt[0]
+  };
+  memcpy(Buf, Inst, sizeof(Inst));
+
+  write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
+  write32le(Buf + 7, Index);
+  write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+}
+
+template <class ELFT> bool X86_64<ELFT>::isPicRel(uint32_t Type) const {
+  return Type != R_X86_64_PC32 && Type != R_X86_64_32 &&
+         Type != R_X86_64_TPOFF32;
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+                                  uint64_t Val) const {
+  // Convert
+  //   .byte 0x66
+  //   leaq x@tlsgd(%rip), %rdi
+  //   .word 0x6666
+  //   rex64
+  //   call __tls_get_addr@plt
+  // to
+  //   mov %fs:0x0,%rax
+  //   lea x@tpoff,%rax
+  const uint8_t Inst[] = {
+      0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
+      0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00              // lea x@tpoff,%rax
+  };
+  memcpy(Loc - 4, Inst, sizeof(Inst));
+
+  // The original code used a pc relative relocation and so we have to
+  // compensate for the -4 in had in the addend.
+  write32le(Loc + 8, Val + 4);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+                                  uint64_t Val) const {
+  // Convert
+  //   .byte 0x66
+  //   leaq x@tlsgd(%rip), %rdi
+  //   .word 0x6666
+  //   rex64
+  //   call __tls_get_addr@plt
+  // to
+  //   mov %fs:0x0,%rax
+  //   addq x@tpoff,%rax
+  const uint8_t Inst[] = {
+      0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
+      0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00              // addq x@tpoff,%rax
+  };
+  memcpy(Loc - 4, Inst, sizeof(Inst));
+
+  // Both code sequences are PC relatives, but since we are moving the constant
+  // forward by 8 bytes we have to subtract the value by 8.
+  write32le(Loc + 8, Val - 8);
+}
+
+// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
+// R_X86_64_TPOFF32 so that it does not use GOT.
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                  uint64_t Val) const {
+  uint8_t *Inst = Loc - 3;
+  uint8_t Reg = Loc[-1] >> 3;
+  uint8_t *RegSlot = Loc - 1;
+
+  // Note that ADD with RSP or R12 is converted to ADD instead of LEA
+  // because LEA with these registers needs 4 bytes to encode and thus
+  // wouldn't fit the space.
+
+  if (memcmp(Inst, "\x48\x03\x25", 3) == 0) {
+    // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
+    memcpy(Inst, "\x48\x81\xc4", 3);
+  } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) {
+    // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
+    memcpy(Inst, "\x49\x81\xc4", 3);
+  } else if (memcmp(Inst, "\x4c\x03", 2) == 0) {
+    // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
+    memcpy(Inst, "\x4d\x8d", 2);
+    *RegSlot = 0x80 | (Reg << 3) | Reg;
+  } else if (memcmp(Inst, "\x48\x03", 2) == 0) {
+    // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
+    memcpy(Inst, "\x48\x8d", 2);
+    *RegSlot = 0x80 | (Reg << 3) | Reg;
+  } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) {
+    // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
+    memcpy(Inst, "\x49\xc7", 2);
+    *RegSlot = 0xc0 | Reg;
+  } else if (memcmp(Inst, "\x48\x8b", 2) == 0) {
+    // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
+    memcpy(Inst, "\x48\xc7", 2);
+    *RegSlot = 0xc0 | Reg;
+  } else {
+    error(getErrorLocation(Loc - 3) +
+          "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
+  }
+
+  // The original code used a PC relative relocation.
+  // Need to compensate for the -4 it had in the addend.
+  write32le(Loc, Val + 4);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+                                  uint64_t Val) const {
+  // Convert
+  //   leaq bar@tlsld(%rip), %rdi
+  //   callq __tls_get_addr@PLT
+  //   leaq bar@dtpoff(%rax), %rcx
+  // to
+  //   .word 0x6666
+  //   .byte 0x66
+  //   mov %fs:0,%rax
+  //   leaq bar@tpoff(%rax), %rcx
+  if (Type == R_X86_64_DTPOFF64) {
+    write64le(Loc, Val);
+    return;
+  }
+  if (Type == R_X86_64_DTPOFF32) {
+    write32le(Loc, Val);
+    return;
+  }
+
+  const uint8_t Inst[] = {
+      0x66, 0x66,                                          // .word 0x6666
+      0x66,                                                // .byte 0x66
+      0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax
+  };
+  memcpy(Loc - 3, Inst, sizeof(Inst));
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
+                               uint64_t Val) const {
+  switch (Type) {
+  case R_X86_64_8:
+    checkUInt<8>(Loc, Val, Type);
+    *Loc = Val;
+    break;
+  case R_X86_64_16:
+    checkUInt<16>(Loc, Val, Type);
+    write16le(Loc, Val);
+    break;
+  case R_X86_64_32:
+    checkUInt<32>(Loc, Val, Type);
+    write32le(Loc, Val);
+    break;
+  case R_X86_64_32S:
+  case R_X86_64_TPOFF32:
+  case R_X86_64_GOT32:
+  case R_X86_64_GOTPCREL:
+  case R_X86_64_GOTPCRELX:
+  case R_X86_64_REX_GOTPCRELX:
+  case R_X86_64_PC32:
+  case R_X86_64_GOTTPOFF:
+  case R_X86_64_PLT32:
+  case R_X86_64_TLSGD:
+  case R_X86_64_TLSLD:
+  case R_X86_64_DTPOFF32:
+  case R_X86_64_SIZE32:
+    checkInt<32>(Loc, Val, Type);
+    write32le(Loc, Val);
+    break;
+  case R_X86_64_64:
+  case R_X86_64_DTPOFF64:
+  case R_X86_64_GLOB_DAT:
+  case R_X86_64_PC64:
+  case R_X86_64_SIZE64:
+  case R_X86_64_GOT64:
+    write64le(Loc, Val);
+    break;
+  default:
+    llvm_unreachable("unexpected relocation");
+  }
+}
+
+template <class ELFT>
+RelExpr X86_64<ELFT>::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                                      RelExpr RelExpr) const {
+  if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)
+    return RelExpr;
+  const uint8_t Op = Data[-2];
+  const uint8_t ModRm = Data[-1];
+
+  // FIXME: When PIC is disabled and foo is defined locally in the
+  // lower 32 bit address space, memory operand in mov can be converted into
+  // immediate operand. Otherwise, mov must be changed to lea. We support only
+  // latter relaxation at this moment.
+  if (Op == 0x8b)
+    return R_RELAX_GOT_PC;
+
+  // Relax call and jmp.
+  if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))
+    return R_RELAX_GOT_PC;
+
+  // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor.
+  // If PIC then no relaxation is available.
+  // We also don't relax test/binop instructions without REX byte,
+  // they are 32bit operations and not common to have.
+  assert(Type == R_X86_64_REX_GOTPCRELX);
+  return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC;
+}
+
+// A subset of relaxations can only be applied for no-PIC. This method
+// handles such relaxations. Instructions encoding information was taken from:
+// "Intel 64 and IA-32 Architectures Software Developer's Manual V2"
+// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
+//    64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
+template <class ELFT>
+void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
+                                 uint8_t ModRm) const {
+  const uint8_t Rex = Loc[-3];
+  // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".
+  if (Op == 0x85) {
+    // See "TEST-Logical Compare" (4-428 Vol. 2B),
+    // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).
+
+    // ModR/M byte has form XX YYY ZZZ, where
+    // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).
+    // XX has different meanings:
+    // 00: The operand's memory address is in reg1.
+    // 01: The operand's memory address is reg1 + a byte-sized displacement.
+    // 10: The operand's memory address is reg1 + a word-sized displacement.
+    // 11: The operand is reg1 itself.
+    // If an instruction requires only one operand, the unused reg2 field
+    // holds extra opcode bits rather than a register code
+    // 0xC0 == 11 000 000 binary.
+    // 0x38 == 00 111 000 binary.
+    // We transfer reg2 to reg1 here as operand.
+    // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).
+    Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.
+
+    // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32
+    // See "TEST-Logical Compare" (4-428 Vol. 2B).
+    Loc[-2] = 0xf7;
+
+    // Move R bit to the B bit in REX byte.
+    // REX byte is encoded as 0100WRXB, where
+    // 0100 is 4bit fixed pattern.
+    // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the
+    //   default operand size is used (which is 32-bit for most but not all
+    //   instructions).
+    // REX.R This 1-bit value is an extension to the MODRM.reg field.
+    // REX.X This 1-bit value is an extension to the SIB.index field.
+    // REX.B This 1-bit value is an extension to the MODRM.rm field or the
+    // SIB.base field.
+    // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
+    Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+    write32le(Loc, Val);
+    return;
+  }
+
+  // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub
+  // or xor operations.
+
+  // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg".
+  // Logic is close to one for test instruction above, but we also
+  // write opcode extension here, see below for details.
+  Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte.
+
+  // Primary opcode is 0x81, opcode extension is one of:
+  // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB,
+  // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP.
+  // This value was wrote to MODRM.reg in a line above.
+  // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15),
+  // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for
+  // descriptions about each operation.
+  Loc[-2] = 0x81;
+  Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+  write32le(Loc, Val);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
+  const uint8_t Op = Loc[-2];
+  const uint8_t ModRm = Loc[-1];
+
+  // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
+  if (Op == 0x8b) {
+    Loc[-2] = 0x8d;
+    write32le(Loc, Val);
+    return;
+  }
+
+  if (Op != 0xff) {
+    // We are relaxing a rip relative to an absolute, so compensate
+    // for the old -4 addend.
+    assert(!Config->Pic);
+    relaxGotNoPic(Loc, Val + 4, Op, ModRm);
+    return;
+  }
+
+  // Convert call/jmp instructions.
+  if (ModRm == 0x15) {
+    // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo".
+    // Instead we convert to "addr32 call foo" where addr32 is an instruction
+    // prefix. That makes result expression to be a single instruction.
+    Loc[-2] = 0x67; // addr32 prefix
+    Loc[-1] = 0xe8; // call
+    write32le(Loc, Val);
+    return;
+  }
+
+  // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop".
+  // jmp doesn't return, so it is fine to use nop here, it is just a stub.
+  assert(ModRm == 0x25);
+  Loc[-2] = 0xe9; // jmp
+  Loc[3] = 0x90;  // nop
+  write32le(Loc - 1, Val + 1);
+}
+
+TargetInfo *elf::getX32TargetInfo() {
+  static X86_64<ELF32LE> Target;
+  return &Target;
+}
+
+TargetInfo *elf::getX86_64TargetInfo() {
+  static X86_64<ELF64LE> Target;
+  return &Target;
+}
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
new file mode 100644 (file)
index 0000000..77243bd
--- /dev/null
@@ -0,0 +1,75 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ELFOptionsTableGen)
+
+if(NOT LLD_BUILT_STANDALONE)
+  set(tablegen_deps intrinsics_gen)
+endif()
+
+add_lld_library(lldELF
+  Arch/AArch64.cpp
+  Arch/AMDGPU.cpp
+  Arch/ARM.cpp
+  Arch/AVR.cpp
+  Arch/Mips.cpp
+  Arch/MipsArchTree.cpp
+  Arch/PPC.cpp
+  Arch/PPC64.cpp
+  Arch/SPARCV9.cpp
+  Arch/X86.cpp
+  Arch/X86_64.cpp
+  Driver.cpp
+  DriverUtils.cpp
+  EhFrame.cpp
+  Error.cpp
+  Filesystem.cpp
+  GdbIndex.cpp
+  ICF.cpp
+  InputFiles.cpp
+  InputSection.cpp
+  LTO.cpp
+  LinkerScript.cpp
+  MapFile.cpp
+  MarkLive.cpp
+  OutputSections.cpp
+  Relocations.cpp
+  ScriptLexer.cpp
+  ScriptParser.cpp
+  Strings.cpp
+  SymbolTable.cpp
+  Symbols.cpp
+  SyntheticSections.cpp
+  Target.cpp
+  Thunks.cpp
+  Writer.cpp
+
+  LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  Analysis
+  BinaryFormat
+  BitReader
+  BitWriter
+  Codegen
+  Core
+  DebugInfoDWARF
+  Demangle
+  IPO
+  Linker
+  LTO
+  Object
+  Option
+  Passes
+  MC
+  Support
+  Target
+  TransformUtils
+
+  LINK_LIBS
+  lldConfig
+  lldCore
+  ${LLVM_PTHREAD_LIB}
+
+  DEPENDS
+  ELFOptionsTableGen
+  ${tablegen_deps}
+  )
diff --git a/ELF/Config.h b/ELF/Config.h
new file mode 100644 (file)
index 0000000..23627dd
--- /dev/null
@@ -0,0 +1,238 @@
+//===- Config.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_CONFIG_H
+#define LLD_ELF_CONFIG_H
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Endian.h"
+
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class InputFile;
+struct Symbol;
+
+enum ELFKind {
+  ELFNoneKind,
+  ELF32LEKind,
+  ELF32BEKind,
+  ELF64LEKind,
+  ELF64BEKind
+};
+
+// For --build-id.
+enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
+
+// For --discard-{all,locals,none}.
+enum class DiscardPolicy { Default, All, Locals, None };
+
+// For --strip-{all,debug}.
+enum class StripPolicy { None, All, Debug };
+
+// For --unresolved-symbols.
+enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll };
+
+// For --sort-section and linkerscript sorting rules.
+enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
+
+// For --target2
+enum class Target2Policy { Abs, Rel, GotRel };
+
+struct SymbolVersion {
+  llvm::StringRef Name;
+  bool IsExternCpp;
+  bool HasWildcard;
+};
+
+// This struct contains symbols version definition that
+// can be found in version script if it is used for link.
+struct VersionDefinition {
+  llvm::StringRef Name;
+  uint16_t Id = 0;
+  std::vector<SymbolVersion> Globals;
+  size_t NameOff = 0; // Offset in the string table
+};
+
+// Structure for mapping renamed symbols
+struct RenamedSymbol {
+  Symbol *Target;
+  uint8_t OriginalBinding;
+};
+
+// This struct contains the global configuration for the linker.
+// Most fields are direct mapping from the command line options
+// and such fields have the same name as the corresponding options.
+// Most fields are initialized by the driver.
+struct Configuration {
+  InputFile *FirstElf = nullptr;
+  uint8_t OSABI = 0;
+  llvm::CachePruningPolicy ThinLTOCachePolicy;
+  llvm::StringMap<uint64_t> SectionStartMap;
+  llvm::StringRef DynamicLinker;
+  llvm::StringRef Entry;
+  llvm::StringRef Emulation;
+  llvm::StringRef Fini;
+  llvm::StringRef Init;
+  llvm::StringRef LTOAAPipeline;
+  llvm::StringRef LTONewPmPasses;
+  llvm::StringRef MapFile;
+  llvm::StringRef OutputFile;
+  llvm::StringRef OptRemarksFilename;
+  llvm::StringRef SoName;
+  llvm::StringRef Sysroot;
+  llvm::StringRef ThinLTOCacheDir;
+  std::string Rpath;
+  std::vector<VersionDefinition> VersionDefinitions;
+  std::vector<llvm::StringRef> Argv;
+  std::vector<llvm::StringRef> AuxiliaryList;
+  std::vector<llvm::StringRef> FilterList;
+  std::vector<llvm::StringRef> SearchPaths;
+  std::vector<llvm::StringRef> SymbolOrderingFile;
+  std::vector<llvm::StringRef> Undefined;
+  std::vector<SymbolVersion> VersionScriptGlobals;
+  std::vector<SymbolVersion> VersionScriptLocals;
+  std::vector<uint8_t> BuildIdVector;
+  llvm::MapVector<Symbol *, RenamedSymbol> RenamedSymbols;
+  bool AllowMultipleDefinition;
+  bool AsNeeded = false;
+  bool Bsymbolic;
+  bool BsymbolicFunctions;
+  bool ColorDiagnostics = false;
+  bool CompressDebugSections;
+  bool DefineCommon;
+  bool Demangle = true;
+  bool DisableVerify;
+  bool EhFrameHdr;
+  bool EmitRelocs;
+  bool EnableNewDtags;
+  bool ExportDynamic;
+  bool FatalWarnings;
+  bool GcSections;
+  bool GdbIndex;
+  bool GnuHash;
+  bool ICF;
+  bool MipsN32Abi = false;
+  bool NoGnuUnique;
+  bool NoUndefinedVersion;
+  bool Nostdlib;
+  bool OFormatBinary;
+  bool Omagic;
+  bool OptRemarksWithHotness;
+  bool Pie;
+  bool PrintGcSections;
+  bool Relocatable;
+  bool SaveTemps;
+  bool SingleRoRx;
+  bool Shared;
+  bool Static = false;
+  bool SysvHash;
+  bool Target1Rel;
+  bool Threads;
+  bool Trace;
+  bool Verbose;
+  bool WarnCommon;
+  bool WarnMissingEntry;
+  bool ZCombreloc;
+  bool ZExecstack;
+  bool ZNocopyreloc;
+  bool ZNodelete;
+  bool ZNodlopen;
+  bool ZNow;
+  bool ZOrigin;
+  bool ZRelro;
+  bool ZRodynamic;
+  bool ZText;
+  bool ExitEarly;
+  bool ZWxneeded;
+  DiscardPolicy Discard;
+  SortSectionPolicy SortSection;
+  StripPolicy Strip;
+  UnresolvedPolicy UnresolvedSymbols;
+  Target2Policy Target2;
+  BuildIdKind BuildId = BuildIdKind::None;
+  ELFKind EKind = ELFNoneKind;
+  uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
+  uint16_t EMachine = llvm::ELF::EM_NONE;
+  uint64_t ErrorLimit = 20;
+  uint64_t ImageBase;
+  uint64_t MaxPageSize;
+  uint64_t ZStackSize;
+  unsigned LTOPartitions;
+  unsigned LTOO;
+  unsigned Optimize;
+  unsigned ThinLTOJobs;
+
+  // The following config options do not directly correspond to any
+  // particualr command line options.
+
+  // True if we need to pass through relocations in input files to the
+  // output file. Usually false because we consume relocations.
+  bool CopyRelocs;
+
+  // True if the target is ELF64. False if ELF32.
+  bool Is64;
+
+  // True if the target is little-endian. False if big-endian.
+  bool IsLE;
+
+  // endianness::little if IsLE is true. endianness::big otherwise.
+  llvm::support::endianness Endianness;
+
+  // True if the target is the little-endian MIPS64.
+  //
+  // The reason why we have this variable only for the MIPS is because
+  // we use this often.  Some ELF headers for MIPS64EL are in a
+  // mixed-endian (which is horrible and I'd say that's a serious spec
+  // bug), and we need to know whether we are reading MIPS ELF files or
+  // not in various places.
+  //
+  // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official
+  // name whatever that means. A fun hypothesis is that "EL" is short for
+  // little-endian written in the little-endian order, but I don't know
+  // if that's true.)
+  bool IsMips64EL;
+
+  // The ELF spec defines two types of relocation table entries, RELA and
+  // REL. RELA is a triplet of (offset, info, addend) while REL is a
+  // tuple of (offset, info). Addends for REL are implicit and read from
+  // the location where the relocations are applied. So, REL is more
+  // compact than RELA but requires a bit of more work to process.
+  //
+  // (From the linker writer's view, this distinction is not necessary.
+  // If the ELF had chosen whichever and sticked with it, it would have
+  // been easier to write code to process relocations, but it's too late
+  // to change the spec.)
+  //
+  // Each ABI defines its relocation type. IsRela is true if target
+  // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A
+  // few 32-bit ABIs are using RELA too.
+  bool IsRela;
+
+  // True if we are creating position-independent code.
+  bool Pic;
+
+  // 4 for ELF32, 8 for ELF64.
+  int Wordsize;
+};
+
+// The only instance of Configuration struct.
+extern Configuration *Config;
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
new file mode 100644 (file)
index 0000000..47a50bb
--- /dev/null
@@ -0,0 +1,1061 @@
+//===- Driver.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The driver drives the entire linking process. It is responsible for
+// parsing command line options and doing whatever it is instructed to do.
+//
+// One notable thing in the LLD's driver when compared to other linkers is
+// that the LLD's driver is agnostic on the host operating system.
+// Other linkers usually have implicit default values (such as a dynamic
+// linker path or library paths) for each host OS.
+//
+// I don't think implicit default values are useful because they are
+// usually explicitly specified by the compiler driver. They can even
+// be harmful when you are doing cross-linking. Therefore, in LLD, we
+// simply trust the compiler driver to pass all required options and
+// don't try to make effort on our side.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Config.h"
+#include "Error.h"
+#include "Filesystem.h"
+#include "ICF.h"
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "ScriptParser.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Threads.h"
+#include "Writer.h"
+#include "lld/Config/Version.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TarWriter.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::sys;
+
+using namespace lld;
+using namespace lld::elf;
+
+Configuration *elf::Config;
+LinkerDriver *elf::Driver;
+
+BumpPtrAllocator elf::BAlloc;
+StringSaver elf::Saver{BAlloc};
+std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances;
+
+static void setConfigs();
+
+bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
+               raw_ostream &Error) {
+  ErrorCount = 0;
+  ErrorOS = &Error;
+  InputSections.clear();
+  Tar = nullptr;
+
+  Config = make<Configuration>();
+  Driver = make<LinkerDriver>();
+  Script = make<LinkerScript>();
+  Config->Argv = {Args.begin(), Args.end()};
+
+  Driver->main(Args, CanExitEarly);
+  freeArena();
+  return !ErrorCount;
+}
+
+// Parses a linker -m option.
+static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
+  uint8_t OSABI = 0;
+  StringRef S = Emul;
+  if (S.endswith("_fbsd")) {
+    S = S.drop_back(5);
+    OSABI = ELFOSABI_FREEBSD;
+  }
+
+  std::pair<ELFKind, uint16_t> Ret =
+      StringSwitch<std::pair<ELFKind, uint16_t>>(S)
+          .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
+          .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
+          .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
+          .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
+          .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+          .Case("elf32ppc", {ELF32BEKind, EM_PPC})
+          .Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
+          .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
+          .Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+          .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
+          .Case("elf_i386", {ELF32LEKind, EM_386})
+          .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
+          .Default({ELFNoneKind, EM_NONE});
+
+  if (Ret.first == ELFNoneKind) {
+    if (S == "i386pe" || S == "i386pep" || S == "thumb2pe")
+      error("Windows targets are not supported on the ELF frontend: " + Emul);
+    else
+      error("unknown emulation: " + Emul);
+  }
+  return std::make_tuple(Ret.first, Ret.second, OSABI);
+}
+
+// Returns slices of MB by parsing MB as an archive file.
+// Each slice consists of a member file in the archive.
+std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
+    MemoryBufferRef MB) {
+  std::unique_ptr<Archive> File =
+      check(Archive::create(MB),
+            MB.getBufferIdentifier() + ": failed to parse archive");
+
+  std::vector<std::pair<MemoryBufferRef, uint64_t>> V;
+  Error Err = Error::success();
+  for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+    Archive::Child C =
+        check(COrErr, MB.getBufferIdentifier() +
+                          ": could not get the child of the archive");
+    MemoryBufferRef MBRef =
+        check(C.getMemoryBufferRef(),
+              MB.getBufferIdentifier() +
+                  ": could not get the buffer for a child of the archive");
+    V.push_back(std::make_pair(MBRef, C.getChildOffset()));
+  }
+  if (Err)
+    fatal(MB.getBufferIdentifier() + ": Archive::children failed: " +
+          toString(std::move(Err)));
+
+  // Take ownership of memory buffers created for members of thin archives.
+  for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers())
+    make<std::unique_ptr<MemoryBuffer>>(std::move(MB));
+
+  return V;
+}
+
+// Opens a file and create a file object. Path has to be resolved already.
+void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
+  using namespace sys::fs;
+
+  Optional<MemoryBufferRef> Buffer = readFile(Path);
+  if (!Buffer.hasValue())
+    return;
+  MemoryBufferRef MBRef = *Buffer;
+
+  if (InBinary) {
+    Files.push_back(make<BinaryFile>(MBRef));
+    return;
+  }
+
+  switch (identify_magic(MBRef.getBuffer())) {
+  case file_magic::unknown:
+    readLinkerScript(MBRef);
+    return;
+  case file_magic::archive: {
+    // Handle -whole-archive.
+    if (InWholeArchive) {
+      for (const auto &P : getArchiveMembers(MBRef))
+        Files.push_back(createObjectFile(P.first, Path, P.second));
+      return;
+    }
+
+    std::unique_ptr<Archive> File =
+        check(Archive::create(MBRef), Path + ": failed to parse archive");
+
+    // If an archive file has no symbol table, it is likely that a user
+    // is attempting LTO and using a default ar command that doesn't
+    // understand the LLVM bitcode file. It is a pretty common error, so
+    // we'll handle it as if it had a symbol table.
+    if (!File->isEmpty() && !File->hasSymbolTable()) {
+      for (const auto &P : getArchiveMembers(MBRef))
+        Files.push_back(make<LazyObjectFile>(P.first, Path, P.second));
+      return;
+    }
+
+    // Handle the regular case.
+    Files.push_back(make<ArchiveFile>(std::move(File)));
+    return;
+  }
+  case file_magic::elf_shared_object:
+    if (Config->Relocatable) {
+      error("attempted static link of dynamic object " + Path);
+      return;
+    }
+
+    // DSOs usually have DT_SONAME tags in their ELF headers, and the
+    // sonames are used to identify DSOs. But if they are missing,
+    // they are identified by filenames. We don't know whether the new
+    // file has a DT_SONAME or not because we haven't parsed it yet.
+    // Here, we set the default soname for the file because we might
+    // need it later.
+    //
+    // If a file was specified by -lfoo, the directory part is not
+    // significant, as a user did not specify it. This behavior is
+    // compatible with GNU.
+    Files.push_back(
+        createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
+    return;
+  default:
+    if (InLib)
+      Files.push_back(make<LazyObjectFile>(MBRef, "", 0));
+    else
+      Files.push_back(createObjectFile(MBRef));
+  }
+}
+
+// Add a given library by searching it from input search paths.
+void LinkerDriver::addLibrary(StringRef Name) {
+  if (Optional<std::string> Path = searchLibrary(Name))
+    addFile(*Path, /*WithLOption=*/true);
+  else
+    error("unable to find library -l" + Name);
+}
+
+// This function is called on startup. We need this for LTO since
+// LTO calls LLVM functions to compile bitcode files to native code.
+// Technically this can be delayed until we read bitcode files, but
+// we don't bother to do lazily because the initialization is fast.
+static void initLLVM(opt::InputArgList &Args) {
+  InitializeAllTargets();
+  InitializeAllTargetMCs();
+  InitializeAllAsmPrinters();
+  InitializeAllAsmParsers();
+
+  // Parse and evaluate -mllvm options.
+  std::vector<const char *> V;
+  V.push_back("lld (LLVM option parsing)");
+  for (auto *Arg : Args.filtered(OPT_mllvm))
+    V.push_back(Arg->getValue());
+  cl::ParseCommandLineOptions(V.size(), V.data());
+}
+
+// Some command line options or some combinations of them are not allowed.
+// This function checks for such errors.
+static void checkOptions(opt::InputArgList &Args) {
+  // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup
+  // table which is a relatively new feature.
+  if (Config->EMachine == EM_MIPS && Config->GnuHash)
+    error("the .gnu.hash section is not compatible with the MIPS target.");
+
+  if (Config->Pie && Config->Shared)
+    error("-shared and -pie may not be used together");
+
+  if (!Config->Shared && !Config->FilterList.empty())
+    error("-F may not be used without -shared");
+
+  if (!Config->Shared && !Config->AuxiliaryList.empty())
+    error("-f may not be used without -shared");
+
+  if (Config->Relocatable) {
+    if (Config->Shared)
+      error("-r and -shared may not be used together");
+    if (Config->GcSections)
+      error("-r and --gc-sections may not be used together");
+    if (Config->ICF)
+      error("-r and --icf may not be used together");
+    if (Config->Pie)
+      error("-r and -pie may not be used together");
+  }
+}
+
+static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
+  int V = Default;
+  if (auto *Arg = Args.getLastArg(Key)) {
+    StringRef S = Arg->getValue();
+    if (!to_integer(S, V, 10))
+      error(Arg->getSpelling() + ": number expected, but got " + S);
+  }
+  return V;
+}
+
+static const char *getReproduceOption(opt::InputArgList &Args) {
+  if (auto *Arg = Args.getLastArg(OPT_reproduce))
+    return Arg->getValue();
+  return getenv("LLD_REPRODUCE");
+}
+
+static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
+  for (auto *Arg : Args.filtered(OPT_z))
+    if (Key == Arg->getValue())
+      return true;
+  return false;
+}
+
+static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key,
+                                uint64_t Default) {
+  for (auto *Arg : Args.filtered(OPT_z)) {
+    std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
+    if (KV.first == Key) {
+      uint64_t Result = Default;
+      if (!to_integer(KV.second, Result))
+        error("invalid " + Key + ": " + KV.second);
+      return Result;
+    }
+  }
+  return Default;
+}
+
+void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
+  ELFOptTable Parser;
+  opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+
+  // Interpret this flag early because error() depends on them.
+  Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20);
+
+  // Handle -help
+  if (Args.hasArg(OPT_help)) {
+    printHelp(ArgsArr[0]);
+    return;
+  }
+
+  // Handle -v or -version.
+  //
+  // A note about "compatible with GNU linkers" message: this is a hack for
+  // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and
+  // still the newest version in March 2017) or earlier to recognize LLD as
+  // a GNU compatible linker. As long as an output for the -v option
+  // contains "GNU" or "with BFD", they recognize us as GNU-compatible.
+  //
+  // This is somewhat ugly hack, but in reality, we had no choice other
+  // than doing this. Considering the very long release cycle of Libtool,
+  // it is not easy to improve it to recognize LLD as a GNU compatible
+  // linker in a timely manner. Even if we can make it, there are still a
+  // lot of "configure" scripts out there that are generated by old version
+  // of Libtool. We cannot convince every software developer to migrate to
+  // the latest version and re-generate scripts. So we have this hack.
+  if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
+    message(getLLDVersion() + " (compatible with GNU linkers)");
+
+  // ld.bfd always exits after printing out the version string.
+  // ld.gold proceeds if a given option is -v. Because gold's behavior
+  // is more permissive than ld.bfd, we chose what gold does here.
+  if (Args.hasArg(OPT_version))
+    return;
+
+  Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown);
+
+  if (const char *Path = getReproduceOption(Args)) {
+    // Note that --reproduce is a debug option so you can ignore it
+    // if you are trying to understand the whole picture of the code.
+    Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
+        TarWriter::create(Path, path::stem(Path));
+    if (ErrOrWriter) {
+      Tar = ErrOrWriter->get();
+      Tar->append("response.txt", createResponseFile(Args));
+      Tar->append("version.txt", getLLDVersion() + "\n");
+      make<std::unique_ptr<TarWriter>>(std::move(*ErrOrWriter));
+    } else {
+      error(Twine("--reproduce: failed to open ") + Path + ": " +
+            toString(ErrOrWriter.takeError()));
+    }
+  }
+
+  readConfigs(Args);
+  initLLVM(Args);
+  createFiles(Args);
+  inferMachineType();
+  setConfigs();
+  checkOptions(Args);
+  if (ErrorCount)
+    return;
+
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    link<ELF32LE>(Args);
+    return;
+  case ELF32BEKind:
+    link<ELF32BE>(Args);
+    return;
+  case ELF64LEKind:
+    link<ELF64LE>(Args);
+    return;
+  case ELF64BEKind:
+    link<ELF64BE>(Args);
+    return;
+  default:
+    llvm_unreachable("unknown Config->EKind");
+  }
+}
+
+static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
+                   bool Default) {
+  if (auto *Arg = Args.getLastArg(K1, K2))
+    return Arg->getOption().getID() == K1;
+  return Default;
+}
+
+static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) {
+  std::vector<StringRef> V;
+  for (auto *Arg : Args.filtered(Id))
+    V.push_back(Arg->getValue());
+  return V;
+}
+
+static std::string getRpath(opt::InputArgList &Args) {
+  std::vector<StringRef> V = getArgs(Args, OPT_rpath);
+  return llvm::join(V.begin(), V.end(), ":");
+}
+
+// Determines what we should do if there are remaining unresolved
+// symbols after the name resolution.
+static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
+  // -noinhibit-exec or -r imply some default values.
+  if (Args.hasArg(OPT_noinhibit_exec))
+    return UnresolvedPolicy::WarnAll;
+  if (Args.hasArg(OPT_relocatable))
+    return UnresolvedPolicy::IgnoreAll;
+
+  UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols,
+                                        OPT_warn_unresolved_symbols, true)
+                                     ? UnresolvedPolicy::ReportError
+                                     : UnresolvedPolicy::Warn;
+
+  // Process the last of -unresolved-symbols, -no-undefined or -z defs.
+  for (auto *Arg : llvm::reverse(Args)) {
+    switch (Arg->getOption().getID()) {
+    case OPT_unresolved_symbols: {
+      StringRef S = Arg->getValue();
+      if (S == "ignore-all" || S == "ignore-in-object-files")
+        return UnresolvedPolicy::Ignore;
+      if (S == "ignore-in-shared-libs" || S == "report-all")
+        return ErrorOrWarn;
+      error("unknown --unresolved-symbols value: " + S);
+      continue;
+    }
+    case OPT_no_undefined:
+      return ErrorOrWarn;
+    case OPT_z:
+      if (StringRef(Arg->getValue()) == "defs")
+        return ErrorOrWarn;
+      continue;
+    }
+  }
+
+  // -shared implies -unresolved-symbols=ignore-all because missing
+  // symbols are likely to be resolved at runtime using other DSOs.
+  if (Config->Shared)
+    return UnresolvedPolicy::Ignore;
+  return ErrorOrWarn;
+}
+
+static Target2Policy getTarget2(opt::InputArgList &Args) {
+  StringRef S = Args.getLastArgValue(OPT_target2, "got-rel");
+  if (S == "rel")
+    return Target2Policy::Rel;
+  if (S == "abs")
+    return Target2Policy::Abs;
+  if (S == "got-rel")
+    return Target2Policy::GotRel;
+  error("unknown --target2 option: " + S);
+  return Target2Policy::GotRel;
+}
+
+static bool isOutputFormatBinary(opt::InputArgList &Args) {
+  if (auto *Arg = Args.getLastArg(OPT_oformat)) {
+    StringRef S = Arg->getValue();
+    if (S == "binary")
+      return true;
+    error("unknown --oformat value: " + S);
+  }
+  return false;
+}
+
+static DiscardPolicy getDiscard(opt::InputArgList &Args) {
+  if (Args.hasArg(OPT_relocatable))
+    return DiscardPolicy::None;
+
+  auto *Arg =
+      Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
+  if (!Arg)
+    return DiscardPolicy::Default;
+  if (Arg->getOption().getID() == OPT_discard_all)
+    return DiscardPolicy::All;
+  if (Arg->getOption().getID() == OPT_discard_locals)
+    return DiscardPolicy::Locals;
+  return DiscardPolicy::None;
+}
+
+static StringRef getDynamicLinker(opt::InputArgList &Args) {
+  auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
+  if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker)
+    return "";
+  return Arg->getValue();
+}
+
+static StripPolicy getStrip(opt::InputArgList &Args) {
+  if (Args.hasArg(OPT_relocatable))
+    return StripPolicy::None;
+
+  auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug);
+  if (!Arg)
+    return StripPolicy::None;
+  if (Arg->getOption().getID() == OPT_strip_all)
+    return StripPolicy::All;
+  return StripPolicy::Debug;
+}
+
+static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) {
+  uint64_t VA = 0;
+  if (S.startswith("0x"))
+    S = S.drop_front(2);
+  if (!to_integer(S, VA, 16))
+    error("invalid argument: " + toString(Arg));
+  return VA;
+}
+
+static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) {
+  StringMap<uint64_t> Ret;
+  for (auto *Arg : Args.filtered(OPT_section_start)) {
+    StringRef Name;
+    StringRef Addr;
+    std::tie(Name, Addr) = StringRef(Arg->getValue()).split('=');
+    Ret[Name] = parseSectionAddress(Addr, Arg);
+  }
+
+  if (auto *Arg = Args.getLastArg(OPT_Ttext))
+    Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg);
+  if (auto *Arg = Args.getLastArg(OPT_Tdata))
+    Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg);
+  if (auto *Arg = Args.getLastArg(OPT_Tbss))
+    Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg);
+  return Ret;
+}
+
+static SortSectionPolicy getSortSection(opt::InputArgList &Args) {
+  StringRef S = Args.getLastArgValue(OPT_sort_section);
+  if (S == "alignment")
+    return SortSectionPolicy::Alignment;
+  if (S == "name")
+    return SortSectionPolicy::Name;
+  if (!S.empty())
+    error("unknown --sort-section rule: " + S);
+  return SortSectionPolicy::Default;
+}
+
+static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {
+  StringRef S = Args.getLastArgValue(OPT_hash_style, "sysv");
+  if (S == "sysv")
+    return {true, false};
+  if (S == "gnu")
+    return {false, true};
+  if (S != "both")
+    error("unknown -hash-style: " + S);
+  return {true, true};
+}
+
+// Parse --build-id or --build-id=<style>. We handle "tree" as a
+// synonym for "sha1" because all our hash functions including
+// -build-id=sha1 are actually tree hashes for performance reasons.
+static std::pair<BuildIdKind, std::vector<uint8_t>>
+getBuildId(opt::InputArgList &Args) {
+  auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq);
+  if (!Arg)
+    return {BuildIdKind::None, {}};
+
+  if (Arg->getOption().getID() == OPT_build_id)
+    return {BuildIdKind::Fast, {}};
+
+  StringRef S = Arg->getValue();
+  if (S == "md5")
+    return {BuildIdKind::Md5, {}};
+  if (S == "sha1" || S == "tree")
+    return {BuildIdKind::Sha1, {}};
+  if (S == "uuid")
+    return {BuildIdKind::Uuid, {}};
+  if (S.startswith("0x"))
+    return {BuildIdKind::Hexstring, parseHex(S.substr(2))};
+
+  if (S != "none")
+    error("unknown --build-id style: " + S);
+  return {BuildIdKind::None, {}};
+}
+
+static std::vector<StringRef> getLines(MemoryBufferRef MB) {
+  SmallVector<StringRef, 0> Arr;
+  MB.getBuffer().split(Arr, '\n');
+
+  std::vector<StringRef> Ret;
+  for (StringRef S : Arr) {
+    S = S.trim();
+    if (!S.empty())
+      Ret.push_back(S);
+  }
+  return Ret;
+}
+
+static bool getCompressDebugSections(opt::InputArgList &Args) {
+  StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
+  if (S == "none")
+    return false;
+  if (S != "zlib")
+    error("unknown --compress-debug-sections value: " + S);
+  if (!zlib::isAvailable())
+    error("--compress-debug-sections: zlib is not available");
+  return true;
+}
+
+// Initializes Config members by the command line options.
+void LinkerDriver::readConfigs(opt::InputArgList &Args) {
+  Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
+  Config->AuxiliaryList = getArgs(Args, OPT_auxiliary);
+  Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
+  Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+  Config->CompressDebugSections = getCompressDebugSections(Args);
+  Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
+                                !Args.hasArg(OPT_relocatable));
+  Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
+  Config->DisableVerify = Args.hasArg(OPT_disable_verify);
+  Config->Discard = getDiscard(Args);
+  Config->DynamicLinker = getDynamicLinker(Args);
+  Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
+  Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
+  Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
+  Config->Entry = Args.getLastArgValue(OPT_entry);
+  Config->ExportDynamic =
+      getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
+  Config->FatalWarnings =
+      getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+  Config->FilterList = getArgs(Args, OPT_filter);
+  Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
+  Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false);
+  Config->GdbIndex = Args.hasArg(OPT_gdb_index);
+  Config->ICF = getArg(Args, OPT_icf_all, OPT_icf_none, false);
+  Config->Init = Args.getLastArgValue(OPT_init, "_init");
+  Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+  Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
+  Config->LTOO = getInteger(Args, OPT_lto_O, 2);
+  Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
+  Config->MapFile = Args.getLastArgValue(OPT_Map);
+  Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
+  Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
+  Config->Nostdlib = Args.hasArg(OPT_nostdlib);
+  Config->OFormatBinary = isOutputFormatBinary(Args);
+  Config->Omagic = Args.hasArg(OPT_omagic);
+  Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename);
+  Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness);
+  Config->Optimize = getInteger(Args, OPT_O, 1);
+  Config->OutputFile = Args.getLastArgValue(OPT_o);
+  Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
+  Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
+  Config->Rpath = getRpath(Args);
+  Config->Relocatable = Args.hasArg(OPT_relocatable);
+  Config->SaveTemps = Args.hasArg(OPT_save_temps);
+  Config->SearchPaths = getArgs(Args, OPT_L);
+  Config->SectionStartMap = getSectionStartMap(Args);
+  Config->Shared = Args.hasArg(OPT_shared);
+  Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+  Config->SoName = Args.getLastArgValue(OPT_soname);
+  Config->SortSection = getSortSection(Args);
+  Config->Strip = getStrip(Args);
+  Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
+  Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false);
+  Config->Target2 = getTarget2(Args);
+  Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
+  Config->ThinLTOCachePolicy = check(
+      parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
+      "--thinlto-cache-policy: invalid cache policy");
+  Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
+  Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);
+  Config->Trace = Args.hasArg(OPT_trace);
+  Config->Undefined = getArgs(Args, OPT_undefined);
+  Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
+  Config->Verbose = Args.hasArg(OPT_verbose);
+  Config->WarnCommon = Args.hasArg(OPT_warn_common);
+  Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
+  Config->ZExecstack = hasZOption(Args, "execstack");
+  Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
+  Config->ZNodelete = hasZOption(Args, "nodelete");
+  Config->ZNodlopen = hasZOption(Args, "nodlopen");
+  Config->ZNow = hasZOption(Args, "now");
+  Config->ZOrigin = hasZOption(Args, "origin");
+  Config->ZRelro = !hasZOption(Args, "norelro");
+  Config->ZRodynamic = hasZOption(Args, "rodynamic");
+  Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);
+  Config->ZText = !hasZOption(Args, "notext");
+  Config->ZWxneeded = hasZOption(Args, "wxneeded");
+
+  if (Config->LTOO > 3)
+    error("invalid optimization level for LTO: " +
+          Args.getLastArgValue(OPT_lto_O));
+  if (Config->LTOPartitions == 0)
+    error("--lto-partitions: number of threads must be > 0");
+  if (Config->ThinLTOJobs == 0)
+    error("--thinlto-jobs: number of threads must be > 0");
+
+  if (auto *Arg = Args.getLastArg(OPT_m)) {
+    // Parse ELF{32,64}{LE,BE} and CPU type.
+    StringRef S = Arg->getValue();
+    std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
+        parseEmulation(S);
+    Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
+    Config->Emulation = S;
+  }
+
+  if (Args.hasArg(OPT_print_map))
+    Config->MapFile = "-";
+
+  // --omagic is an option to create old-fashioned executables in which
+  // .text segments are writable. Today, the option is still in use to
+  // create special-purpose programs such as boot loaders. It doesn't
+  // make sense to create PT_GNU_RELRO for such executables.
+  if (Config->Omagic)
+    Config->ZRelro = false;
+
+  std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args);
+  std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
+
+  if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
+    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+      Config->SymbolOrderingFile = getLines(*Buffer);
+
+  // If --retain-symbol-file is used, we'll keep only the symbols listed in
+  // the file and discard all others.
+  if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) {
+    Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+      for (StringRef S : getLines(*Buffer))
+        Config->VersionScriptGlobals.push_back(
+            {S, /*IsExternCpp*/ false, /*HasWildcard*/ false});
+  }
+
+  bool HasExportDynamic =
+      getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
+
+  // Parses -dynamic-list and -export-dynamic-symbol. They make some
+  // symbols private. Note that -export-dynamic takes precedence over them
+  // as it says all symbols should be exported.
+  if (!HasExportDynamic) {
+    for (auto *Arg : Args.filtered(OPT_dynamic_list))
+      if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+        readDynamicList(*Buffer);
+
+    for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+      Config->VersionScriptGlobals.push_back(
+          {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
+
+    // Dynamic lists are a simplified linker script that doesn't need the
+    // "global:" and implicitly ends with a "local:*". Set the variables
+    // needed to simulate that.
+    if (Args.hasArg(OPT_dynamic_list) ||
+        Args.hasArg(OPT_export_dynamic_symbol)) {
+      Config->ExportDynamic = true;
+      if (!Config->Shared)
+        Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+    }
+  }
+
+  if (auto *Arg = Args.getLastArg(OPT_version_script))
+    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+      readVersionScript(*Buffer);
+}
+
+// Some Config members do not directly correspond to any particular
+// command line options, but computed based on other Config values.
+// This function initialize such members. See Config.h for the details
+// of these values.
+static void setConfigs() {
+  ELFKind Kind = Config->EKind;
+  uint16_t Machine = Config->EMachine;
+
+  // There is an ILP32 ABI for x86-64, although it's not very popular.
+  // It is called the x32 ABI.
+  bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
+
+  Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
+  Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
+  Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
+  Config->Endianness =
+      Config->IsLE ? support::endianness::little : support::endianness::big;
+  Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
+  Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
+  Config->Pic = Config->Pie || Config->Shared;
+  Config->Wordsize = Config->Is64 ? 8 : 4;
+}
+
+// Returns a value of "-format" option.
+static bool getBinaryOption(StringRef S) {
+  if (S == "binary")
+    return true;
+  if (S == "elf" || S == "default")
+    return false;
+  error("unknown -format value: " + S +
+        " (supported formats: elf, default, binary)");
+  return false;
+}
+
+void LinkerDriver::createFiles(opt::InputArgList &Args) {
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_l:
+      addLibrary(Arg->getValue());
+      break;
+    case OPT_INPUT:
+      addFile(Arg->getValue(), /*WithLOption=*/false);
+      break;
+    case OPT_alias_script_T:
+    case OPT_script:
+      if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue()))
+        readLinkerScript(*MB);
+      break;
+    case OPT_as_needed:
+      Config->AsNeeded = true;
+      break;
+    case OPT_format:
+      InBinary = getBinaryOption(Arg->getValue());
+      break;
+    case OPT_no_as_needed:
+      Config->AsNeeded = false;
+      break;
+    case OPT_Bstatic:
+      Config->Static = true;
+      break;
+    case OPT_Bdynamic:
+      Config->Static = false;
+      break;
+    case OPT_whole_archive:
+      InWholeArchive = true;
+      break;
+    case OPT_no_whole_archive:
+      InWholeArchive = false;
+      break;
+    case OPT_start_lib:
+      InLib = true;
+      break;
+    case OPT_end_lib:
+      InLib = false;
+      break;
+    }
+  }
+
+  if (Files.empty() && ErrorCount == 0)
+    error("no input files");
+}
+
+// If -m <machine_type> was not given, infer it from object files.
+void LinkerDriver::inferMachineType() {
+  if (Config->EKind != ELFNoneKind)
+    return;
+
+  for (InputFile *F : Files) {
+    if (F->EKind == ELFNoneKind)
+      continue;
+    Config->EKind = F->EKind;
+    Config->EMachine = F->EMachine;
+    Config->OSABI = F->OSABI;
+    Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F);
+    return;
+  }
+  error("target emulation unknown: -m or at least one .o file required");
+}
+
+// Parse -z max-page-size=<value>. The default value is defined by
+// each target.
+static uint64_t getMaxPageSize(opt::InputArgList &Args) {
+  uint64_t Val =
+      getZOptionValue(Args, "max-page-size", Target->DefaultMaxPageSize);
+  if (!isPowerOf2_64(Val))
+    error("max-page-size: value isn't a power of 2");
+  return Val;
+}
+
+// Parses -image-base option.
+static uint64_t getImageBase(opt::InputArgList &Args) {
+  // Use default if no -image-base option is given.
+  // Because we are using "Target" here, this function
+  // has to be called after the variable is initialized.
+  auto *Arg = Args.getLastArg(OPT_image_base);
+  if (!Arg)
+    return Config->Pic ? 0 : Target->DefaultImageBase;
+
+  StringRef S = Arg->getValue();
+  uint64_t V;
+  if (!to_integer(S, V)) {
+    error("-image-base: number expected, but got " + S);
+    return 0;
+  }
+  if ((V % Config->MaxPageSize) != 0)
+    warn("-image-base: address isn't multiple of page size: " + S);
+  return V;
+}
+
+// Parses --defsym=alias option.
+static std::vector<std::pair<StringRef, StringRef>>
+getDefsym(opt::InputArgList &Args) {
+  std::vector<std::pair<StringRef, StringRef>> Ret;
+  for (auto *Arg : Args.filtered(OPT_defsym)) {
+    StringRef From;
+    StringRef To;
+    std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+    if (!isValidCIdentifier(To))
+      error("--defsym: symbol name expected, but got " + To);
+    Ret.push_back({From, To});
+  }
+  return Ret;
+}
+
+// Parses `--exclude-libs=lib,lib,...`.
+// The library names may be delimited by commas or colons.
+static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
+  DenseSet<StringRef> Ret;
+  for (auto *Arg : Args.filtered(OPT_exclude_libs)) {
+    StringRef S = Arg->getValue();
+    for (;;) {
+      size_t Pos = S.find_first_of(",:");
+      if (Pos == StringRef::npos)
+        break;
+      Ret.insert(S.substr(0, Pos));
+      S = S.substr(Pos + 1);
+    }
+    Ret.insert(S);
+  }
+  return Ret;
+}
+
+// Handles the -exclude-libs option. If a static library file is specified
+// by the -exclude-libs option, all public symbols from the archive become
+// private unless otherwise specified by version scripts or something.
+// A special library name "ALL" means all archive files.
+//
+// This is not a popular option, but some programs such as bionic libc use it.
+static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
+  DenseSet<StringRef> Libs = getExcludeLibs(Args);
+  bool All = Libs.count("ALL");
+
+  for (InputFile *File : Files)
+    if (auto *F = dyn_cast<ArchiveFile>(File))
+      if (All || Libs.count(path::filename(F->getName())))
+        for (Symbol *Sym : F->getSymbols())
+          Sym->VersionId = VER_NDX_LOCAL;
+}
+
+// Do actual linking. Note that when this function is called,
+// all linker scripts have already been parsed.
+template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
+  SymbolTable<ELFT> Symtab;
+  elf::Symtab<ELFT>::X = &Symtab;
+  Target = getTarget();
+
+  Config->MaxPageSize = getMaxPageSize(Args);
+  Config->ImageBase = getImageBase(Args);
+
+  // Default output filename is "a.out" by the Unix tradition.
+  if (Config->OutputFile.empty())
+    Config->OutputFile = "a.out";
+
+  // Fail early if the output file or map file is not writable. If a user has a
+  // long link, e.g. due to a large LTO link, they do not wish to run it and
+  // find that it failed because there was a mistake in their command-line.
+  if (auto E = tryCreateFile(Config->OutputFile))
+    error("cannot open output file " + Config->OutputFile + ": " + E.message());
+  if (auto E = tryCreateFile(Config->MapFile))
+    error("cannot open map file " + Config->MapFile + ": " + E.message());
+  if (ErrorCount)
+    return;
+
+  // Use default entry point name if no name was given via the command
+  // line nor linker scripts. For some reason, MIPS entry point name is
+  // different from others.
+  Config->WarnMissingEntry =
+      (!Config->Entry.empty() || (!Config->Shared && !Config->Relocatable));
+  if (Config->Entry.empty() && !Config->Relocatable)
+    Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
+
+  // Handle --trace-symbol.
+  for (auto *Arg : Args.filtered(OPT_trace_symbol))
+    Symtab.trace(Arg->getValue());
+
+  // Add all files to the symbol table. This will add almost all
+  // symbols that we need to the symbol table.
+  for (InputFile *F : Files)
+    Symtab.addFile(F);
+
+  // If an entry symbol is in a static archive, pull out that file now
+  // to complete the symbol table. After this, no new names except a
+  // few linker-synthesized ones will be added to the symbol table.
+  if (Symtab.find(Config->Entry))
+    Symtab.addUndefined(Config->Entry);
+
+  // Return if there were name resolution errors.
+  if (ErrorCount)
+    return;
+
+  // Handle the `--undefined <sym>` options.
+  Symtab.scanUndefinedFlags();
+
+  // Handle undefined symbols in DSOs.
+  Symtab.scanShlibUndefined();
+
+  // Handle the -exclude-libs option.
+  if (Args.hasArg(OPT_exclude_libs))
+    excludeLibs(Args, Files);
+
+  // Apply version scripts.
+  Symtab.scanVersionScript();
+
+  // Create wrapped symbols for -wrap option.
+  for (auto *Arg : Args.filtered(OPT_wrap))
+    Symtab.addSymbolWrap(Arg->getValue());
+
+  // Create alias symbols for -defsym option.
+  for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
+    Symtab.addSymbolAlias(Def.first, Def.second);
+
+  Symtab.addCombinedLTOObject();
+  if (ErrorCount)
+    return;
+
+  // Some symbols (such as __ehdr_start) are defined lazily only when there
+  // are undefined symbols for them, so we add these to trigger that logic.
+  for (StringRef Sym : Script->Opt.ReferencedSymbols)
+    Symtab.addUndefined(Sym);
+
+  // Apply symbol renames for -wrap and -defsym
+  Symtab.applySymbolRenames();
+
+  // Now that we have a complete list of input files.
+  // Beyond this point, no new files are added.
+  // Aggregate all input sections into one place.
+  for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles())
+    for (InputSectionBase *S : F->getSections())
+      if (S && S != &InputSection::Discarded)
+        InputSections.push_back(S);
+  for (BinaryFile *F : Symtab.getBinaryFiles())
+    for (InputSectionBase *S : F->getSections())
+      InputSections.push_back(cast<InputSection>(S));
+
+  // This adds a .comment section containing a version string. We have to add it
+  // before decompressAndMergeSections because the .comment section is a
+  // mergeable section.
+  if (!Config->Relocatable)
+    InputSections.push_back(createCommentSection<ELFT>());
+
+  // Do size optimizations: garbage collection, merging of SHF_MERGE sections
+  // and identical code folding.
+  if (Config->GcSections)
+    markLive<ELFT>();
+  decompressAndMergeSections();
+  if (Config->ICF)
+    doIcf<ELFT>();
+
+  // Write the result to the file.
+  writeResult<ELFT>();
+}
diff --git a/ELF/Driver.h b/ELF/Driver.h
new file mode 100644 (file)
index 0000000..076dda7
--- /dev/null
@@ -0,0 +1,75 @@
+//===- Driver.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_DRIVER_H
+#define LLD_ELF_DRIVER_H
+
+#include "SymbolTable.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reproduce.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace elf {
+
+extern class LinkerDriver *Driver;
+
+class LinkerDriver {
+public:
+  void main(ArrayRef<const char *> Args, bool CanExitEarly);
+  void addFile(StringRef Path, bool WithLOption);
+  void addLibrary(StringRef Name);
+
+private:
+  void readConfigs(llvm::opt::InputArgList &Args);
+  void createFiles(llvm::opt::InputArgList &Args);
+  void inferMachineType();
+  template <class ELFT> void link(llvm::opt::InputArgList &Args);
+
+  // True if we are in --whole-archive and --no-whole-archive.
+  bool InWholeArchive = false;
+
+  // True if we are in --start-lib and --end-lib.
+  bool InLib = false;
+
+  // True if we are in -format=binary and -format=elf.
+  bool InBinary = false;
+
+  std::vector<InputFile *> Files;
+};
+
+// Parses command line options.
+class ELFOptTable : public llvm::opt::OptTable {
+public:
+  ELFOptTable();
+  llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
+};
+
+// Create enum with OPT_xxx values for each option in Options.td
+enum {
+  OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+void printHelp(const char *Argv0);
+std::string createResponseFile(const llvm::opt::InputArgList &Args);
+
+llvm::Optional<std::string> findFromSearchPaths(StringRef Path);
+llvm::Optional<std::string> searchLibrary(StringRef Path);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
new file mode 100644 (file)
index 0000000..5adb091
--- /dev/null
@@ -0,0 +1,208 @@
+//===- DriverUtils.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the driver. Because there
+// are so many small functions, we created this separate file to make
+// Driver.cpp less cluttered.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Error.h"
+#include "Memory.h"
+#include "lld/Config/Version.h"
+#include "lld/Core/Reproduce.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const opt::OptTable::Info OptInfo[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
+  {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
+   X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
+#include "Options.inc"
+#undef OPTION
+};
+
+ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
+
+// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
+static bool getColorDiagnostics(opt::InputArgList &Args) {
+  auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+                              OPT_no_color_diagnostics);
+  if (!Arg)
+    return ErrorOS->has_colors();
+  if (Arg->getOption().getID() == OPT_color_diagnostics)
+    return true;
+  if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+    return false;
+
+  StringRef S = Arg->getValue();
+  if (S == "auto")
+    return ErrorOS->has_colors();
+  if (S == "always")
+    return true;
+  if (S != "never")
+    error("unknown option: -color-diagnostics=" + S);
+  return false;
+}
+
+static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
+  if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
+    StringRef S = Arg->getValue();
+    if (S != "windows" && S != "posix")
+      error("invalid response file quoting: " + S);
+    if (S == "windows")
+      return cl::TokenizeWindowsCommandLine;
+    return cl::TokenizeGNUCommandLine;
+  }
+  if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
+    return cl::TokenizeWindowsCommandLine;
+  return cl::TokenizeGNUCommandLine;
+}
+
+// Parses a given list of options.
+opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
+  // Make InputArgList from string vectors.
+  unsigned MissingIndex;
+  unsigned MissingCount;
+  SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
+
+  // We need to get the quoting style for response files before parsing all
+  // options so we parse here before and ignore all the options but
+  // --rsp-quoting.
+  opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+
+  // Expand response files (arguments in the form of @<filename>)
+  // and then parse the argument again.
+  cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+  Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+
+  // Interpret -color-diagnostics early so that error messages
+  // for unknown flags are colored.
+  Config->ColorDiagnostics = getColorDiagnostics(Args);
+  if (MissingCount)
+    error(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+
+  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+    error("unknown argument: " + Arg->getSpelling());
+  return Args;
+}
+
+void elf::printHelp(const char *Argv0) {
+  ELFOptTable Table;
+  Table.PrintHelp(outs(), Argv0, "lld", false);
+  outs() << "\n";
+
+  // Scripts generated by Libtool versions up to at least 2.4.6 (the most
+  // recent version as of March 2017) expect /: supported targets:.* elf/
+  // in a message for the -help option. If it doesn't match, the scripts
+  // assume that the linker doesn't support very basic features such as
+  // shared libraries. Therefore, we need to print out at least "elf".
+  // Here, we print out all the targets that we support.
+  outs() << Argv0 << ": supported targets: "
+         << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
+         << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
+         << "elf32-tradlittlemips elf32-x86-64 "
+         << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
+         << "elf64-tradlittlemips elf64-x86-64\n";
+}
+
+// Reconstructs command line arguments so that so that you can re-run
+// the same command with the same inputs. This is for --reproduce.
+std::string elf::createResponseFile(const opt::InputArgList &Args) {
+  SmallString<0> Data;
+  raw_svector_ostream OS(Data);
+
+  // Copy the command line to the output while rewriting paths.
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getID()) {
+    case OPT_reproduce:
+      break;
+    case OPT_INPUT:
+      OS << quote(rewritePath(Arg->getValue())) << "\n";
+      break;
+    case OPT_o:
+      // If -o path contains directories, "lld @response.txt" will likely
+      // fail because the archive we are creating doesn't contain empty
+      // directories for the output path (-o doesn't create directories).
+      // Strip directories to prevent the issue.
+      OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
+      break;
+    case OPT_L:
+    case OPT_dynamic_list:
+    case OPT_rpath:
+    case OPT_alias_script_T:
+    case OPT_script:
+    case OPT_version_script:
+      OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue()))
+         << "\n";
+      break;
+    default:
+      OS << toString(Arg) << "\n";
+    }
+  }
+  return Data.str();
+}
+
+// Find a file by concatenating given paths. If a resulting path
+// starts with "=", the character is replaced with a --sysroot value.
+static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
+  SmallString<128> S;
+  if (Path1.startswith("="))
+    path::append(S, Config->Sysroot, Path1.substr(1), Path2);
+  else
+    path::append(S, Path1, Path2);
+
+  if (fs::exists(S))
+    return S.str().str();
+  return None;
+}
+
+Optional<std::string> elf::findFromSearchPaths(StringRef Path) {
+  for (StringRef Dir : Config->SearchPaths)
+    if (Optional<std::string> S = findFile(Dir, Path))
+      return S;
+  return None;
+}
+
+// This is for -lfoo. We'll look for libfoo.so or libfoo.a from
+// search paths.
+Optional<std::string> elf::searchLibrary(StringRef Name) {
+  if (Name.startswith(":"))
+    return findFromSearchPaths(Name.substr(1));
+
+  for (StringRef Dir : Config->SearchPaths) {
+    if (!Config->Static)
+      if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so"))
+        return S;
+    if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
+      return S;
+  }
+  return None;
+}
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
new file mode 100644 (file)
index 0000000..c4e3f65
--- /dev/null
@@ -0,0 +1,212 @@
+//===- EhFrame.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// .eh_frame section contains information on how to unwind the stack when
+// an exception is thrown. The section consists of sequence of CIE and FDE
+// records. The linker needs to merge CIEs and associate FDEs to CIEs.
+// That means the linker has to understand the format of the section.
+//
+// This file contains a few utility functions to read .eh_frame contents.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EhFrame.h"
+#include "Error.h"
+#include "InputSection.h"
+#include "Relocations.h"
+#include "Strings.h"
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+template <class ELFT> class EhReader {
+public:
+  EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
+  size_t readEhRecordSize();
+  uint8_t getFdeEncoding();
+
+private:
+  template <class P> void failOn(const P *Loc, const Twine &Msg) {
+    fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
+          IS->getObjMsg<ELFT>((const uint8_t *)Loc - IS->Data.data()));
+  }
+
+  uint8_t readByte();
+  void skipBytes(size_t Count);
+  StringRef readString();
+  void skipLeb128();
+  void skipAugP();
+
+  InputSectionBase *IS;
+  ArrayRef<uint8_t> D;
+};
+}
+
+template <class ELFT>
+size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
+  return EhReader<ELFT>(S, S->Data.slice(Off)).readEhRecordSize();
+}
+
+// .eh_frame section is a sequence of records. Each record starts with
+// a 4 byte length field. This function reads the length.
+template <class ELFT> size_t EhReader<ELFT>::readEhRecordSize() {
+  const endianness E = ELFT::TargetEndianness;
+  if (D.size() < 4)
+    failOn(D.data(), "CIE/FDE too small");
+
+  // First 4 bytes of CIE/FDE is the size of the record.
+  // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
+  // but we do not support that format yet.
+  uint64_t V = read32<E>(D.data());
+  if (V == UINT32_MAX)
+    failOn(D.data(), "CIE/FDE too large");
+  uint64_t Size = V + 4;
+  if (Size > D.size())
+    failOn(D.data(), "CIE/FDE ends past the end of the section");
+  return Size;
+}
+
+// Read a byte and advance D by one byte.
+template <class ELFT> uint8_t EhReader<ELFT>::readByte() {
+  if (D.empty())
+    failOn(D.data(), "unexpected end of CIE");
+  uint8_t B = D.front();
+  D = D.slice(1);
+  return B;
+}
+
+template <class ELFT> void EhReader<ELFT>::skipBytes(size_t Count) {
+  if (D.size() < Count)
+    failOn(D.data(), "CIE is too small");
+  D = D.slice(Count);
+}
+
+// Read a null-terminated string.
+template <class ELFT> StringRef EhReader<ELFT>::readString() {
+  const uint8_t *End = std::find(D.begin(), D.end(), '\0');
+  if (End == D.end())
+    failOn(D.data(), "corrupted CIE (failed to read string)");
+  StringRef S = toStringRef(D.slice(0, End - D.begin()));
+  D = D.slice(S.size() + 1);
+  return S;
+}
+
+// Skip an integer encoded in the LEB128 format.
+// Actual number is not of interest because only the runtime needs it.
+// But we need to be at least able to skip it so that we can read
+// the field that follows a LEB128 number.
+template <class ELFT> void EhReader<ELFT>::skipLeb128() {
+  const uint8_t *ErrPos = D.data();
+  while (!D.empty()) {
+    uint8_t Val = D.front();
+    D = D.slice(1);
+    if ((Val & 0x80) == 0)
+      return;
+  }
+  failOn(ErrPos, "corrupted CIE (failed to read LEB128)");
+}
+
+static size_t getAugPSize(unsigned Enc) {
+  switch (Enc & 0x0f) {
+  case DW_EH_PE_absptr:
+  case DW_EH_PE_signed:
+    return Config->Wordsize;
+  case DW_EH_PE_udata2:
+  case DW_EH_PE_sdata2:
+    return 2;
+  case DW_EH_PE_udata4:
+  case DW_EH_PE_sdata4:
+    return 4;
+  case DW_EH_PE_udata8:
+  case DW_EH_PE_sdata8:
+    return 8;
+  }
+  return 0;
+}
+
+template <class ELFT> void EhReader<ELFT>::skipAugP() {
+  uint8_t Enc = readByte();
+  if ((Enc & 0xf0) == DW_EH_PE_aligned)
+    failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported");
+  size_t Size = getAugPSize(Enc);
+  if (Size == 0)
+    failOn(D.data() - 1, "unknown FDE encoding");
+  if (Size >= D.size())
+    failOn(D.data() - 1, "corrupted CIE");
+  D = D.slice(Size);
+}
+
+template <class ELFT> uint8_t elf::getFdeEncoding(EhSectionPiece *P) {
+  auto *IS = static_cast<InputSectionBase *>(P->ID);
+  return EhReader<ELFT>(IS, P->data()).getFdeEncoding();
+}
+
+template <class ELFT> uint8_t EhReader<ELFT>::getFdeEncoding() {
+  skipBytes(8);
+  int Version = readByte();
+  if (Version != 1 && Version != 3)
+    failOn(D.data() - 1,
+           "FDE version 1 or 3 expected, but got " + Twine(Version));
+
+  StringRef Aug = readString();
+
+  // Skip code and data alignment factors.
+  skipLeb128();
+  skipLeb128();
+
+  // Skip the return address register. In CIE version 1 this is a single
+  // byte. In CIE version 3 this is an unsigned LEB128.
+  if (Version == 1)
+    readByte();
+  else
+    skipLeb128();
+
+  // We only care about an 'R' value, but other records may precede an 'R'
+  // record. Unfortunately records are not in TLV (type-length-value) format,
+  // so we need to teach the linker how to skip records for each type.
+  for (char C : Aug) {
+    if (C == 'R')
+      return readByte();
+    if (C == 'z') {
+      skipLeb128();
+      continue;
+    }
+    if (C == 'P') {
+      skipAugP();
+      continue;
+    }
+    if (C == 'L') {
+      readByte();
+      continue;
+    }
+    failOn(Aug.data(), "unknown .eh_frame augmentation string: " + Aug);
+  }
+  return DW_EH_PE_absptr;
+}
+
+template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase *S, size_t Off);
+
+template uint8_t elf::getFdeEncoding<ELF32LE>(EhSectionPiece *P);
+template uint8_t elf::getFdeEncoding<ELF32BE>(EhSectionPiece *P);
+template uint8_t elf::getFdeEncoding<ELF64LE>(EhSectionPiece *P);
+template uint8_t elf::getFdeEncoding<ELF64BE>(EhSectionPiece *P);
diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h
new file mode 100644 (file)
index 0000000..07d1aaa
--- /dev/null
@@ -0,0 +1,25 @@
+//===- EhFrame.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_EHFRAME_H
+#define LLD_ELF_EHFRAME_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+class InputSectionBase;
+struct EhSectionPiece;
+
+template <class ELFT> size_t readEhRecordSize(InputSectionBase *S, size_t Off);
+template <class ELFT> uint8_t getFdeEncoding(EhSectionPiece *P);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Error.cpp b/ELF/Error.cpp
new file mode 100644 (file)
index 0000000..224570e
--- /dev/null
@@ -0,0 +1,116 @@
+//===- Error.cpp ----------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Config.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <mutex>
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#endif
+
+using namespace llvm;
+
+using namespace lld;
+using namespace lld::elf;
+
+uint64_t elf::ErrorCount;
+raw_ostream *elf::ErrorOS;
+
+// The functions defined in this file can be called from multiple threads,
+// but outs() or errs() are not thread-safe. We protect them using a mutex.
+static std::mutex Mu;
+
+// Prints "\n" or does nothing, depending on Msg contents of
+// the previous call of this function.
+static void newline(const Twine &Msg) {
+  // True if the previous error message contained "\n".
+  // We want to separate multi-line error messages with a newline.
+  static bool Flag;
+
+  if (Flag)
+    *ErrorOS << "\n";
+  Flag = (StringRef(Msg.str()).find('\n') != StringRef::npos);
+}
+
+static void print(StringRef S, raw_ostream::Colors C) {
+  *ErrorOS << Config->Argv[0] << ": ";
+  if (Config->ColorDiagnostics) {
+    ErrorOS->changeColor(C, true);
+    *ErrorOS << S;
+    ErrorOS->resetColor();
+  } else {
+    *ErrorOS << S;
+  }
+}
+
+void elf::log(const Twine &Msg) {
+  if (Config->Verbose) {
+    std::lock_guard<std::mutex> Lock(Mu);
+    outs() << Config->Argv[0] << ": " << Msg << "\n";
+    outs().flush();
+  }
+}
+
+void elf::message(const Twine &Msg) {
+  std::lock_guard<std::mutex> Lock(Mu);
+  outs() << Msg << "\n";
+  outs().flush();
+}
+
+void elf::warn(const Twine &Msg) {
+  if (Config->FatalWarnings) {
+    error(Msg);
+    return;
+  }
+
+  std::lock_guard<std::mutex> Lock(Mu);
+  newline(Msg);
+  print("warning: ", raw_ostream::MAGENTA);
+  *ErrorOS << Msg << "\n";
+}
+
+void elf::error(const Twine &Msg) {
+  std::lock_guard<std::mutex> Lock(Mu);
+  newline(Msg);
+
+  if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
+    print("error: ", raw_ostream::RED);
+    *ErrorOS << Msg << "\n";
+  } else if (ErrorCount == Config->ErrorLimit) {
+    print("error: ", raw_ostream::RED);
+    *ErrorOS << "too many errors emitted, stopping now"
+             << " (use -error-limit=0 to see all errors)\n";
+    if (Config->ExitEarly)
+      exitLld(1);
+  }
+
+  ++ErrorCount;
+}
+
+void elf::exitLld(int Val) {
+  // Dealloc/destroy ManagedStatic variables before calling
+  // _exit(). In a non-LTO build, this is a nop. In an LTO
+  // build allows us to get the output of -time-passes.
+  llvm_shutdown();
+
+  outs().flush();
+  errs().flush();
+  _exit(Val);
+}
+
+void elf::fatal(const Twine &Msg) {
+  error(Msg);
+  exitLld(1);
+}
diff --git a/ELF/Error.h b/ELF/Error.h
new file mode 100644 (file)
index 0000000..89bc211
--- /dev/null
@@ -0,0 +1,78 @@
+//===- Error.h --------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// In LLD, we have three levels of errors: fatal, error or warn.
+//
+// Fatal makes the program exit immediately with an error message.
+// You shouldn't use it except for reporting a corrupted input file.
+//
+// Error prints out an error message and increment a global variable
+// ErrorCount to record the fact that we met an error condition. It does
+// not exit, so it is safe for a lld-as-a-library use case. It is generally
+// useful because it can report more than one error in a single run.
+//
+// Warn doesn't do anything but printing out a given message.
+//
+// It is not recommended to use llvm::outs() or llvm::errs() directly
+// in LLD because they are not thread-safe. The functions declared in
+// this file are mutually excluded, so you want to use them instead.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_ERROR_H
+#define LLD_ELF_ERROR_H
+
+#include "lld/Core/LLVM.h"
+
+#include "llvm/Support/Error.h"
+
+namespace lld {
+namespace elf {
+
+extern uint64_t ErrorCount;
+extern llvm::raw_ostream *ErrorOS;
+
+void log(const Twine &Msg);
+void message(const Twine &Msg);
+void warn(const Twine &Msg);
+void error(const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
+
+LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
+
+// check() functions are convenient functions to strip errors
+// from error-or-value objects.
+template <class T> T check(ErrorOr<T> E) {
+  if (auto EC = E.getError())
+    fatal(EC.message());
+  return std::move(*E);
+}
+
+template <class T> T check(Expected<T> E) {
+  if (!E)
+    fatal(llvm::toString(E.takeError()));
+  return std::move(*E);
+}
+
+template <class T> T check(ErrorOr<T> E, const Twine &Prefix) {
+  if (auto EC = E.getError())
+    fatal(Prefix + ": " + EC.message());
+  return std::move(*E);
+}
+
+template <class T> T check(Expected<T> E, const Twine &Prefix) {
+  if (!E)
+    fatal(Prefix + ": " + toString(E.takeError()));
+  return std::move(*E);
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp
new file mode 100644 (file)
index 0000000..d468ae0
--- /dev/null
@@ -0,0 +1,77 @@
+//===- Filesystem.cpp -----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a few utility functions to handle files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Filesystem.h"
+#include "Config.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <thread>
+
+using namespace llvm;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Removes a given file asynchronously. This is a performance hack,
+// so remove this when operating systems are improved.
+//
+// On Linux (and probably on other Unix-like systems), unlink(2) is a
+// noticeably slow system call. As of 2016, unlink takes 250
+// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
+//
+// To create a new result file, we first remove existing file. So, if
+// you repeatedly link a 1 GB program in a regular compile-link-debug
+// cycle, every cycle wastes 250 milliseconds only to remove a file.
+// Since LLD can link a 1 GB binary in about 5 seconds, that waste
+// actually counts.
+//
+// This function spawns a background thread to call unlink.
+// The calling thread returns almost immediately.
+void elf::unlinkAsync(StringRef Path) {
+  if (!Config->Threads || !sys::fs::exists(Config->OutputFile) ||
+      !sys::fs::is_regular_file(Config->OutputFile))
+    return;
+
+  // First, rename Path to avoid race condition. We cannot remove
+  // Path from a different thread because we are now going to create
+  // Path as a new file. If we do that in a different thread, the new
+  // thread can remove the new file.
+  SmallString<128> TempPath;
+  if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath))
+    return;
+  if (sys::fs::rename(Path, TempPath)) {
+    sys::fs::remove(TempPath);
+    return;
+  }
+
+  // Remove TempPath in background.
+  std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach();
+}
+
+// Simulate file creation to see if Path is writable.
+//
+// Determining whether a file is writable or not is amazingly hard,
+// and after all the only reliable way of doing that is to actually
+// create a file. But we don't want to do that in this function
+// because LLD shouldn't update any file if it will end in a failure.
+// We also don't want to reimplement heuristics to determine if a
+// file is writable. So we'll let FileOutputBuffer do the work.
+//
+// FileOutputBuffer doesn't touch a desitnation file until commit()
+// is called. We use that class without calling commit() to predict
+// if the given file is writable.
+std::error_code elf::tryCreateFile(StringRef Path) {
+  if (Path.empty())
+    return std::error_code();
+  return FileOutputBuffer::create(Path, 1).getError();
+}
diff --git a/ELF/Filesystem.h b/ELF/Filesystem.h
new file mode 100644 (file)
index 0000000..dbeadac
--- /dev/null
@@ -0,0 +1,22 @@
+//===- Filesystem.h ---------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_FILESYSTEM_H
+#define LLD_ELF_FILESYSTEM_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+void unlinkAsync(StringRef Path);
+std::error_code tryCreateFile(StringRef Path);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp
new file mode 100644 (file)
index 0000000..99e02d0
--- /dev/null
@@ -0,0 +1,49 @@
+//===- GdbIndex.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The -gdb-index option instructs the linker to emit a .gdb_index section.
+// The section contains information to make gdb startup faster.
+// The format of the section is described at
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GdbIndex.h"
+#include "Memory.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Object/ELFObjectFile.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace lld;
+using namespace lld::elf;
+
+std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) {
+  GdbSymbol *&Sym = Map[Offset];
+  if (Sym)
+    return {false, Sym};
+  Sym = make<GdbSymbol>(Hash, Offset);
+  return {true, Sym};
+}
+
+void GdbHashTab::finalizeContents() {
+  uint32_t Size = std::max<uint32_t>(1024, NextPowerOf2(Map.size() * 4 / 3));
+  uint32_t Mask = Size - 1;
+  Table.resize(Size);
+
+  for (auto &P : Map) {
+    GdbSymbol *Sym = P.second;
+    uint32_t I = Sym->NameHash & Mask;
+    uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+
+    while (Table[I])
+      I = (I + Step) & Mask;
+    Table[I] = Sym;
+  }
+}
diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h
new file mode 100644 (file)
index 0000000..bc024e6
--- /dev/null
@@ -0,0 +1,82 @@
+//===- GdbIndex.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_GDB_INDEX_H
+#define LLD_ELF_GDB_INDEX_H
+
+#include "InputFiles.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+
+class InputSection;
+
+// Struct represents single entry of address area of gdb index.
+struct AddressEntry {
+  InputSection *Section;
+  uint64_t LowAddress;
+  uint64_t HighAddress;
+  uint32_t CuIndex;
+};
+
+// Struct represents single entry of compilation units list area of gdb index.
+// It consist of CU offset in .debug_info section and it's size.
+struct CompilationUnitEntry {
+  uint64_t CuOffset;
+  uint64_t CuLength;
+};
+
+// Represents data about symbol and type names which are used
+// to build symbol table and constant pool area of gdb index.
+struct NameTypeEntry {
+  StringRef Name;
+  uint8_t Type;
+};
+
+// We fill one GdbIndexDataChunk for each object where scan of
+// debug information performed. That information futher used
+// for filling gdb index section areas.
+struct GdbIndexChunk {
+  InputSection *DebugInfoSec;
+  std::vector<AddressEntry> AddressArea;
+  std::vector<CompilationUnitEntry> CompilationUnits;
+  std::vector<NameTypeEntry> NamesAndTypes;
+};
+
+// Element of GdbHashTab hash table.
+struct GdbSymbol {
+  GdbSymbol(uint32_t Hash, size_t Offset)
+      : NameHash(Hash), NameOffset(Offset) {}
+  uint32_t NameHash;
+  size_t NameOffset;
+  size_t CuVectorIndex;
+};
+
+// This class manages the hashed symbol table for the .gdb_index section.
+// The hash value for a table entry is computed by applying an iterative hash
+// function to the symbol's name.
+class GdbHashTab final {
+public:
+  std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset);
+
+  void finalizeContents();
+  size_t getCapacity() { return Table.size(); }
+  GdbSymbol *getSymbol(size_t I) { return Table[I]; }
+
+private:
+  llvm::DenseMap<size_t, GdbSymbol *> Map;
+  std::vector<GdbSymbol *> Table;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
new file mode 100644 (file)
index 0000000..09512a8
--- /dev/null
@@ -0,0 +1,435 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ICF is short for Identical Code Folding. This is a size optimization to
+// identify and merge two or more read-only sections (typically functions)
+// that happened to have the same contents. It usually reduces output size
+// by a few percent.
+//
+// In ICF, two sections are considered identical if they have the same
+// section flags, section data, and relocations. Relocations are tricky,
+// because two relocations are considered the same if they have the same
+// relocation types, values, and if they point to the same sections *in
+// terms of ICF*.
+//
+// Here is an example. If foo and bar defined below are compiled to the
+// same machine instructions, ICF can and should merge the two, although
+// their relocations point to each other.
+//
+//   void foo() { bar(); }
+//   void bar() { foo(); }
+//
+// If you merge the two, their relocations point to the same section and
+// thus you know they are mergeable, but how do you know they are
+// mergeable in the first place? This is not an easy problem to solve.
+//
+// What we are doing in LLD is to partition sections into equivalence
+// classes. Sections in the same equivalence class when the algorithm
+// terminates are considered identical. Here are details:
+//
+// 1. First, we partition sections using their hash values as keys. Hash
+//    values contain section types, section contents and numbers of
+//    relocations. During this step, relocation targets are not taken into
+//    account. We just put sections that apparently differ into different
+//    equivalence classes.
+//
+// 2. Next, for each equivalence class, we visit sections to compare
+//    relocation targets. Relocation targets are considered equivalent if
+//    their targets are in the same equivalence class. Sections with
+//    different relocation targets are put into different equivalence
+//    clases.
+//
+// 3. If we split an equivalence class in step 2, two relocations
+//    previously target the same equivalence class may now target
+//    different equivalence classes. Therefore, we repeat step 2 until a
+//    convergence is obtained.
+//
+// 4. For each equivalence class C, pick an arbitrary section in C, and
+//    merge all the other sections in C with it.
+//
+// For small programs, this algorithm needs 3-5 iterations. For large
+// programs such as Chromium, it takes more than 20 iterations.
+//
+// This algorithm was mentioned as an "optimistic algorithm" in [1],
+// though gold implements a different algorithm than this.
+//
+// We parallelize each step so that multiple threads can work on different
+// equivalence classes concurrently. That gave us a large performance
+// boost when applying ICF on large programs. For example, MSVC link.exe
+// or GNU gold takes 10-20 seconds to apply ICF on Chromium, whose output
+// size is about 1.5 GB, but LLD can finish it in less than 2 seconds on a
+// 2.8 GHz 40 core machine. Even without threading, LLD's ICF is still
+// faster than MSVC or gold though.
+//
+// [1] Safe ICF: Pointer Safe and Unwinding aware Identical Code Folding
+// in the Gold Linker
+// http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36912.pdf
+//
+//===----------------------------------------------------------------------===//
+
+#include "ICF.h"
+#include "Config.h"
+#include "SymbolTable.h"
+#include "Threads.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include <algorithm>
+#include <atomic>
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+namespace {
+template <class ELFT> class ICF {
+public:
+  void run();
+
+private:
+  void segregate(size_t Begin, size_t End, bool Constant);
+
+  template <class RelTy>
+  bool constantEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+                  const InputSection *B, ArrayRef<RelTy> RelsB);
+
+  template <class RelTy>
+  bool variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+                  const InputSection *B, ArrayRef<RelTy> RelsB);
+
+  bool equalsConstant(const InputSection *A, const InputSection *B);
+  bool equalsVariable(const InputSection *A, const InputSection *B);
+
+  size_t findBoundary(size_t Begin, size_t End);
+
+  void forEachClassRange(size_t Begin, size_t End,
+                         std::function<void(size_t, size_t)> Fn);
+
+  void forEachClass(std::function<void(size_t, size_t)> Fn);
+
+  std::vector<InputSection *> Sections;
+
+  // We repeat the main loop while `Repeat` is true.
+  std::atomic<bool> Repeat;
+
+  // The main loop counter.
+  int Cnt = 0;
+
+  // We have two locations for equivalence classes. On the first iteration
+  // of the main loop, Class[0] has a valid value, and Class[1] contains
+  // garbage. We read equivalence classes from slot 0 and write to slot 1.
+  // So, Class[0] represents the current class, and Class[1] represents
+  // the next class. On each iteration, we switch their roles and use them
+  // alternately.
+  //
+  // Why are we doing this? Recall that other threads may be working on
+  // other equivalence classes in parallel. They may read sections that we
+  // are updating. We cannot update equivalence classes in place because
+  // it breaks the invariance that all possibly-identical sections must be
+  // in the same equivalence class at any moment. In other words, the for
+  // loop to update equivalence classes is not atomic, and that is
+  // observable from other threads. By writing new classes to other
+  // places, we can keep the invariance.
+  //
+  // Below, `Current` has the index of the current class, and `Next` has
+  // the index of the next class. If threading is enabled, they are either
+  // (0, 1) or (1, 0).
+  //
+  // Note on single-thread: if that's the case, they are always (0, 0)
+  // because we can safely read the next class without worrying about race
+  // conditions. Using the same location makes this algorithm converge
+  // faster because it uses results of the same iteration earlier.
+  int Current = 0;
+  int Next = 0;
+};
+}
+
+// Returns a hash value for S. Note that the information about
+// relocation targets is not included in the hash value.
+template <class ELFT> static uint32_t getHash(InputSection *S) {
+  return hash_combine(S->Flags, S->getSize(), S->NumRelocations);
+}
+
+// Returns true if section S is subject of ICF.
+static bool isEligible(InputSection *S) {
+  // .init and .fini contains instructions that must be executed to
+  // initialize and finalize the process. They cannot and should not
+  // be merged.
+  return S->Live && (S->Flags & SHF_ALLOC) && (S->Flags & SHF_EXECINSTR) &&
+         !(S->Flags & SHF_WRITE) && S->Name != ".init" && S->Name != ".fini";
+}
+
+// Split an equivalence class into smaller classes.
+template <class ELFT>
+void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
+  // This loop rearranges sections in [Begin, End) so that all sections
+  // that are equal in terms of equals{Constant,Variable} are contiguous
+  // in [Begin, End).
+  //
+  // The algorithm is quadratic in the worst case, but that is not an
+  // issue in practice because the number of the distinct sections in
+  // each range is usually very small.
+
+  while (Begin < End) {
+    // Divide [Begin, End) into two. Let Mid be the start index of the
+    // second group.
+    auto Bound =
+        std::stable_partition(Sections.begin() + Begin + 1,
+                              Sections.begin() + End, [&](InputSection *S) {
+                                if (Constant)
+                                  return equalsConstant(Sections[Begin], S);
+                                return equalsVariable(Sections[Begin], S);
+                              });
+    size_t Mid = Bound - Sections.begin();
+
+    // Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by
+    // updating the sections in [Begin, Mid). We use Mid as an equivalence
+    // class ID because every group ends with a unique index.
+    for (size_t I = Begin; I < Mid; ++I)
+      Sections[I]->Class[Next] = Mid;
+
+    // If we created a group, we need to iterate the main loop again.
+    if (Mid != End)
+      Repeat = true;
+
+    Begin = Mid;
+  }
+}
+
+// Compare two lists of relocations.
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::constantEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+                           const InputSection *B, ArrayRef<RelTy> RelsB) {
+  auto Eq = [&](const RelTy &RA, const RelTy &RB) {
+    if (RA.r_offset != RB.r_offset ||
+        RA.getType(Config->IsMips64EL) != RB.getType(Config->IsMips64EL))
+      return false;
+    uint64_t AddA = getAddend<ELFT>(RA);
+    uint64_t AddB = getAddend<ELFT>(RB);
+
+    SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA);
+    SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB);
+    if (&SA == &SB)
+      return AddA == AddB;
+
+    auto *DA = dyn_cast<DefinedRegular>(&SA);
+    auto *DB = dyn_cast<DefinedRegular>(&SB);
+    if (!DA || !DB)
+      return false;
+
+    // Relocations referring to absolute symbols are constant-equal if their
+    // values are equal.
+    if (!DA->Section || !DB->Section)
+      return !DA->Section && !DB->Section &&
+             DA->Value + AddA == DB->Value + AddB;
+
+    if (DA->Section->kind() != DB->Section->kind())
+      return false;
+
+    // Relocations referring to InputSections are constant-equal if their
+    // section offsets are equal.
+    if (isa<InputSection>(DA->Section))
+      return DA->Value + AddA == DB->Value + AddB;
+
+    // Relocations referring to MergeInputSections are constant-equal if their
+    // offsets in the output section are equal.
+    auto *X = dyn_cast<MergeInputSection>(DA->Section);
+    if (!X)
+      return false;
+    auto *Y = cast<MergeInputSection>(DB->Section);
+    if (X->getParent() != Y->getParent())
+      return false;
+
+    uint64_t OffsetA =
+        SA.isSection() ? X->getOffset(AddA) : X->getOffset(DA->Value) + AddA;
+    uint64_t OffsetB =
+        SB.isSection() ? Y->getOffset(AddB) : Y->getOffset(DB->Value) + AddB;
+    return OffsetA == OffsetB;
+  };
+
+  return RelsA.size() == RelsB.size() &&
+         std::equal(RelsA.begin(), RelsA.end(), RelsB.begin(), Eq);
+}
+
+// Compare "non-moving" part of two InputSections, namely everything
+// except relocation targets.
+template <class ELFT>
+bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
+  if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags ||
+      A->getSize() != B->getSize() || A->Data != B->Data)
+    return false;
+
+  if (A->AreRelocsRela)
+    return constantEq(A, A->template relas<ELFT>(), B,
+                      B->template relas<ELFT>());
+  return constantEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
+}
+
+// Compare two lists of relocations. Returns true if all pairs of
+// relocations point to the same section in terms of ICF.
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+                           const InputSection *B, ArrayRef<RelTy> RelsB) {
+  auto Eq = [&](const RelTy &RA, const RelTy &RB) {
+    // The two sections must be identical.
+    SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA);
+    SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB);
+    if (&SA == &SB)
+      return true;
+
+    auto *DA = cast<DefinedRegular>(&SA);
+    auto *DB = cast<DefinedRegular>(&SB);
+
+    // We already dealt with absolute and non-InputSection symbols in
+    // constantEq, and for InputSections we have already checked everything
+    // except the equivalence class.
+    if (!DA->Section)
+      return true;
+    auto *X = dyn_cast<InputSection>(DA->Section);
+    if (!X)
+      return true;
+    auto *Y = cast<InputSection>(DB->Section);
+
+    // Ineligible sections are in the special equivalence class 0.
+    // They can never be the same in terms of the equivalence class.
+    if (X->Class[Current] == 0)
+      return false;
+
+    return X->Class[Current] == Y->Class[Current];
+  };
+
+  return std::equal(RelsA.begin(), RelsA.end(), RelsB.begin(), Eq);
+}
+
+// Compare "moving" part of two InputSections, namely relocation targets.
+template <class ELFT>
+bool ICF<ELFT>::equalsVariable(const InputSection *A, const InputSection *B) {
+  if (A->AreRelocsRela)
+    return variableEq(A, A->template relas<ELFT>(), B,
+                      B->template relas<ELFT>());
+  return variableEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
+}
+
+template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
+  uint32_t Class = Sections[Begin]->Class[Current];
+  for (size_t I = Begin + 1; I < End; ++I)
+    if (Class != Sections[I]->Class[Current])
+      return I;
+  return End;
+}
+
+// Sections in the same equivalence class are contiguous in Sections
+// vector. Therefore, Sections vector can be considered as contiguous
+// groups of sections, grouped by the class.
+//
+// This function calls Fn on every group that starts within [Begin, End).
+// Note that a group must start in that range but doesn't necessarily
+// have to end before End.
+template <class ELFT>
+void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
+                                  std::function<void(size_t, size_t)> Fn) {
+  if (Begin > 0)
+    Begin = findBoundary(Begin - 1, End);
+
+  while (Begin < End) {
+    size_t Mid = findBoundary(Begin, Sections.size());
+    Fn(Begin, Mid);
+    Begin = Mid;
+  }
+}
+
+// Call Fn on each equivalence class.
+template <class ELFT>
+void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
+  // If threading is disabled or the number of sections are
+  // too small to use threading, call Fn sequentially.
+  if (!Config->Threads || Sections.size() < 1024) {
+    forEachClassRange(0, Sections.size(), Fn);
+    ++Cnt;
+    return;
+  }
+
+  Current = Cnt % 2;
+  Next = (Cnt + 1) % 2;
+
+  // Split sections into 256 shards and call Fn in parallel.
+  size_t NumShards = 256;
+  size_t Step = Sections.size() / NumShards;
+  parallelForEachN(0, NumShards, [&](size_t I) {
+    size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step;
+    forEachClassRange(I * Step, End, Fn);
+  });
+  ++Cnt;
+}
+
+// The main function of ICF.
+template <class ELFT> void ICF<ELFT>::run() {
+  // Collect sections to merge.
+  for (InputSectionBase *Sec : InputSections)
+    if (auto *S = dyn_cast<InputSection>(Sec))
+      if (isEligible(S))
+        Sections.push_back(S);
+
+  // Initially, we use hash values to partition sections.
+  for (InputSection *S : Sections)
+    // Set MSB to 1 to avoid collisions with non-hash IDs.
+    S->Class[0] = getHash<ELFT>(S) | (1 << 31);
+
+  // From now on, sections in Sections vector are ordered so that sections
+  // in the same equivalence class are consecutive in the vector.
+  std::stable_sort(Sections.begin(), Sections.end(),
+                   [](InputSection *A, InputSection *B) {
+                     return A->Class[0] < B->Class[0];
+                   });
+
+  // Compare static contents and assign unique IDs for each static content.
+  forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
+
+  // Split groups by comparing relocations until convergence is obtained.
+  do {
+    Repeat = false;
+    forEachClass(
+        [&](size_t Begin, size_t End) { segregate(Begin, End, false); });
+  } while (Repeat);
+
+  log("ICF needed " + Twine(Cnt) + " iterations");
+
+  // Merge sections by the equivalence class.
+  forEachClass([&](size_t Begin, size_t End) {
+    if (End - Begin == 1)
+      return;
+
+    log("selected " + Sections[Begin]->Name);
+    for (size_t I = Begin + 1; I < End; ++I) {
+      log("  removed " + Sections[I]->Name);
+      Sections[Begin]->replace(Sections[I]);
+    }
+  });
+
+  // Mark ARM Exception Index table sections that refer to folded code
+  // sections as not live. These sections have an implict dependency
+  // via the link order dependency.
+  if (Config->EMachine == EM_ARM)
+    for (InputSectionBase *Sec : InputSections)
+      if (auto *S = dyn_cast<InputSection>(Sec))
+        if (S->Flags & SHF_LINK_ORDER)
+          S->Live = S->getLinkOrderDep()->Live;
+}
+
+// ICF entry point function.
+template <class ELFT> void elf::doIcf() { ICF<ELFT>().run(); }
+
+template void elf::doIcf<ELF32LE>();
+template void elf::doIcf<ELF32BE>();
+template void elf::doIcf<ELF64LE>();
+template void elf::doIcf<ELF64BE>();
diff --git a/ELF/ICF.h b/ELF/ICF.h
new file mode 100644 (file)
index 0000000..2421985
--- /dev/null
+++ b/ELF/ICF.h
@@ -0,0 +1,19 @@
+//===- ICF.h --------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_ICF_H
+#define LLD_ELF_ICF_H
+
+namespace lld {
+namespace elf {
+template <class ELFT> void doIcf();
+}
+} // namespace lld
+
+#endif
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
new file mode 100644 (file)
index 0000000..c609615
--- /dev/null
@@ -0,0 +1,1109 @@
+//===- InputFiles.cpp -----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Error.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TarWriter.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::sys::fs;
+
+using namespace lld;
+using namespace lld::elf;
+
+TarWriter *elf::Tar;
+
+InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+
+namespace {
+// In ELF object file all section addresses are zero. If we have multiple
+// .text sections (when using -ffunction-section or comdat group) then
+// LLVM DWARF parser will not be able to parse .debug_line correctly, unless
+// we assign each section some unique address. This callback method assigns
+// each section an address equal to its offset in ELF object file.
+class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> {
+public:
+  uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
+    return static_cast<const ELFSectionRef &>(Sec).getOffset();
+  }
+};
+}
+
+Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
+  log(Path);
+  auto MBOrErr = MemoryBuffer::getFile(Path);
+  if (auto EC = MBOrErr.getError()) {
+    error("cannot open " + Path + ": " + EC.message());
+    return None;
+  }
+
+  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+  MemoryBufferRef MBRef = MB->getMemBufferRef();
+  make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
+
+  if (Tar)
+    Tar->append(relativeToRoot(Path), MBRef.getBuffer());
+  return MBRef;
+}
+
+template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
+  std::unique_ptr<object::ObjectFile> Obj =
+      check(object::ObjectFile::createObjectFile(this->MB), toString(this));
+
+  ObjectInfo ObjInfo;
+  DWARFContextInMemory Dwarf(*Obj, &ObjInfo);
+  DwarfLine.reset(new DWARFDebugLine);
+  DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE,
+                              Config->Wordsize);
+
+  // The second parameter is offset in .debug_line section
+  // for compilation unit (CU) of interest. We have only one
+  // CU (object file), so offset is always 0.
+  DwarfLine->getOrParseLineTable(LineData, 0);
+}
+
+// Returns source line information for a given offset
+// using DWARF debug info.
+template <class ELFT>
+Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S,
+                                                          uint64_t Offset) {
+  llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); });
+
+  // The offset to CU is 0.
+  const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
+  if (!Tbl)
+    return None;
+
+  // Use fake address calcuated by adding section file offset and offset in
+  // section. See comments for ObjectInfo class.
+  DILineInfo Info;
+  Tbl->getFileLineInfoForAddress(
+      S->getOffsetInFile() + Offset, nullptr,
+      DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
+  if (Info.Line == 0)
+    return None;
+  return Info;
+}
+
+// Returns source line information for a given offset
+// using DWARF debug info.
+template <class ELFT>
+std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
+                                               uint64_t Offset) {
+  if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
+    return Info->FileName + ":" + std::to_string(Info->Line);
+  return "";
+}
+
+// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
+std::string lld::toString(const InputFile *F) {
+  if (!F)
+    return "<internal>";
+
+  if (F->ToStringCache.empty()) {
+    if (F->ArchiveName.empty())
+      F->ToStringCache = F->getName();
+    else
+      F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str();
+  }
+  return F->ToStringCache;
+}
+
+template <class ELFT>
+ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
+  if (ELFT::TargetEndianness == support::little)
+    EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
+  else
+    EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
+
+  EMachine = getObj().getHeader()->e_machine;
+  OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
+}
+
+template <class ELFT>
+typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() {
+  return makeArrayRef(Symbols.begin() + FirstNonLocal, Symbols.end());
+}
+
+template <class ELFT>
+uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
+  return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX),
+               toString(this));
+}
+
+template <class ELFT>
+void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
+                                   const Elf_Shdr *Symtab) {
+  FirstNonLocal = Symtab->sh_info;
+  Symbols = check(getObj().symbols(Symtab), toString(this));
+  if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size())
+    fatal(toString(this) + ": invalid sh_info in symbol table");
+
+  StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections),
+                      toString(this));
+}
+
+template <class ELFT>
+elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M, StringRef ArchiveName)
+    : ELFFileBase<ELFT>(Base::ObjectKind, M) {
+  this->ArchiveName = ArchiveName;
+}
+
+template <class ELFT>
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
+  if (this->SymbolBodies.empty())
+    return this->SymbolBodies;
+  return makeArrayRef(this->SymbolBodies).slice(1, this->FirstNonLocal - 1);
+}
+
+template <class ELFT>
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() {
+  if (this->SymbolBodies.empty())
+    return this->SymbolBodies;
+  return makeArrayRef(this->SymbolBodies).slice(1);
+}
+
+template <class ELFT>
+void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+  // Read section and symbol tables.
+  initializeSections(ComdatGroups);
+  initializeSymbols();
+}
+
+// Sections with SHT_GROUP and comdat bits define comdat section groups.
+// They are identified and deduplicated by group name. This function
+// returns a group name.
+template <class ELFT>
+StringRef
+elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
+                                            const Elf_Shdr &Sec) {
+  // Group signatures are stored as symbol names in object files.
+  // sh_info contains a symbol index, so we fetch a symbol and read its name.
+  if (this->Symbols.empty())
+    this->initSymtab(
+        Sections,
+        check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this)));
+
+  const Elf_Sym *Sym = check(
+      object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this));
+  StringRef Signature = check(Sym->getName(this->StringTable), toString(this));
+
+  // As a special case, if a symbol is a section symbol and has no name,
+  // we use a section name as a signature.
+  //
+  // Such SHT_GROUP sections are invalid from the perspective of the ELF
+  // standard, but GNU gold 1.14 (the neweset version as of July 2017) or
+  // older produce such sections as outputs for the -r option, so we need
+  // a bug-compatibility.
+  if (Signature.empty() && Sym->getType() == STT_SECTION)
+    return getSectionName(Sec);
+  return Signature;
+}
+
+template <class ELFT>
+ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
+elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
+  const ELFFile<ELFT> &Obj = this->getObj();
+  ArrayRef<Elf_Word> Entries = check(
+      Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this));
+  if (Entries.empty() || Entries[0] != GRP_COMDAT)
+    fatal(toString(this) + ": unsupported SHT_GROUP format");
+  return Entries.slice(1);
+}
+
+template <class ELFT>
+bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
+  // We don't merge sections if -O0 (default is -O1). This makes sometimes
+  // the linker significantly faster, although the output will be bigger.
+  if (Config->Optimize == 0)
+    return false;
+
+  // Do not merge sections if generating a relocatable object. It makes
+  // the code simpler because we do not need to update relocation addends
+  // to reflect changes introduced by merging. Instead of that we write
+  // such "merge" sections into separate OutputSections and keep SHF_MERGE
+  // / SHF_STRINGS flags and sh_entsize value to be able to perform merging
+  // later during a final linking.
+  if (Config->Relocatable)
+    return false;
+
+  // A mergeable section with size 0 is useless because they don't have
+  // any data to merge. A mergeable string section with size 0 can be
+  // argued as invalid because it doesn't end with a null character.
+  // We'll avoid a mess by handling them as if they were non-mergeable.
+  if (Sec.sh_size == 0)
+    return false;
+
+  // Check for sh_entsize. The ELF spec is not clear about the zero
+  // sh_entsize. It says that "the member [sh_entsize] contains 0 if
+  // the section does not hold a table of fixed-size entries". We know
+  // that Rust 1.13 produces a string mergeable section with a zero
+  // sh_entsize. Here we just accept it rather than being picky about it.
+  uint64_t EntSize = Sec.sh_entsize;
+  if (EntSize == 0)
+    return false;
+  if (Sec.sh_size % EntSize)
+    fatal(toString(this) +
+          ": SHF_MERGE section size must be a multiple of sh_entsize");
+
+  uint64_t Flags = Sec.sh_flags;
+  if (!(Flags & SHF_MERGE))
+    return false;
+  if (Flags & SHF_WRITE)
+    fatal(toString(this) + ": writable SHF_MERGE section is not supported");
+
+  // Don't try to merge if the alignment is larger than the sh_entsize and this
+  // is not SHF_STRINGS.
+  //
+  // Since this is not a SHF_STRINGS, we would need to pad after every entity.
+  // It would be equivalent for the producer of the .o to just set a larger
+  // sh_entsize.
+  if (Flags & SHF_STRINGS)
+    return true;
+
+  return Sec.sh_addralign <= EntSize;
+}
+
+template <class ELFT>
+void elf::ObjectFile<ELFT>::initializeSections(
+    DenseSet<CachedHashStringRef> &ComdatGroups) {
+  const ELFFile<ELFT> &Obj = this->getObj();
+
+  ArrayRef<Elf_Shdr> ObjSections =
+      check(this->getObj().sections(), toString(this));
+  uint64_t Size = ObjSections.size();
+  this->Sections.resize(Size);
+  this->SectionStringTable =
+      check(Obj.getSectionStringTable(ObjSections), toString(this));
+
+  for (size_t I = 0, E = ObjSections.size(); I < E; I++) {
+    if (this->Sections[I] == &InputSection::Discarded)
+      continue;
+    const Elf_Shdr &Sec = ObjSections[I];
+
+    // SHF_EXCLUDE'ed sections are discarded by the linker. However,
+    // if -r is given, we'll let the final link discard such sections.
+    // This is compatible with GNU.
+    if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
+      this->Sections[I] = &InputSection::Discarded;
+      continue;
+    }
+
+    switch (Sec.sh_type) {
+    case SHT_GROUP: {
+      // De-duplicate section groups by their signatures.
+      StringRef Signature = getShtGroupSignature(ObjSections, Sec);
+      bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
+      this->Sections[I] = &InputSection::Discarded;
+
+      // If it is a new section group, we want to keep group members.
+      // Group leader sections, which contain indices of group members, are
+      // discarded because they are useless beyond this point. The only
+      // exception is the -r option because in order to produce re-linkable
+      // object files, we want to pass through basically everything.
+      if (IsNew) {
+        if (Config->Relocatable)
+          this->Sections[I] = createInputSection(Sec);
+        continue;
+      }
+
+      // Otherwise, discard group members.
+      for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
+        if (SecIndex >= Size)
+          fatal(toString(this) +
+                ": invalid section index in group: " + Twine(SecIndex));
+        this->Sections[SecIndex] = &InputSection::Discarded;
+      }
+      break;
+    }
+    case SHT_SYMTAB:
+      this->initSymtab(ObjSections, &Sec);
+      break;
+    case SHT_SYMTAB_SHNDX:
+      this->SymtabSHNDX =
+          check(Obj.getSHNDXTable(Sec, ObjSections), toString(this));
+      break;
+    case SHT_STRTAB:
+    case SHT_NULL:
+      break;
+    default:
+      this->Sections[I] = createInputSection(Sec);
+    }
+
+    // .ARM.exidx sections have a reverse dependency on the InputSection they
+    // have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
+    if (Sec.sh_flags & SHF_LINK_ORDER) {
+      if (Sec.sh_link >= this->Sections.size())
+        fatal(toString(this) + ": invalid sh_link index: " +
+              Twine(Sec.sh_link));
+      this->Sections[Sec.sh_link]->DependentSections.push_back(
+          this->Sections[I]);
+    }
+  }
+}
+
+template <class ELFT>
+InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
+  uint32_t Idx = Sec.sh_info;
+  if (Idx >= this->Sections.size())
+    fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
+  InputSectionBase *Target = this->Sections[Idx];
+
+  // Strictly speaking, a relocation section must be included in the
+  // group of the section it relocates. However, LLVM 3.3 and earlier
+  // would fail to do so, so we gracefully handle that case.
+  if (Target == &InputSection::Discarded)
+    return nullptr;
+
+  if (!Target)
+    fatal(toString(this) + ": unsupported relocation reference");
+  return Target;
+}
+
+// Create a regular InputSection class that has the same contents
+// as a given section.
+InputSectionBase *toRegularSection(MergeInputSection *Sec) {
+  auto *Ret = make<InputSection>(Sec->Flags, Sec->Type, Sec->Alignment,
+                                 Sec->Data, Sec->Name);
+  Ret->File = Sec->File;
+  return Ret;
+}
+
+template <class ELFT>
+InputSectionBase *
+elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
+  StringRef Name = getSectionName(Sec);
+
+  switch (Sec.sh_type) {
+  case SHT_ARM_ATTRIBUTES:
+    // FIXME: ARM meta-data section. Retain the first attribute section
+    // we see. The eglibc ARM dynamic loaders require the presence of an
+    // attribute section for dlopen to work.
+    // In a full implementation we would merge all attribute sections.
+    if (InX::ARMAttributes == nullptr) {
+      InX::ARMAttributes = make<InputSection>(this, &Sec, Name);
+      return InX::ARMAttributes;
+    }
+    return &InputSection::Discarded;
+  case SHT_RELA:
+  case SHT_REL: {
+    // Find the relocation target section and associate this
+    // section with it. Target can be discarded, for example
+    // if it is a duplicated member of SHT_GROUP section, we
+    // do not create or proccess relocatable sections then.
+    InputSectionBase *Target = getRelocTarget(Sec);
+    if (!Target)
+      return nullptr;
+
+    // This section contains relocation information.
+    // If -r is given, we do not interpret or apply relocation
+    // but just copy relocation sections to output.
+    if (Config->Relocatable)
+      return make<InputSection>(this, &Sec, Name);
+
+    if (Target->FirstRelocation)
+      fatal(toString(this) +
+            ": multiple relocation sections to one section are not supported");
+
+    // Mergeable sections with relocations are tricky because relocations
+    // need to be taken into account when comparing section contents for
+    // merging. It's not worth supporting such mergeable sections because
+    // they are rare and it'd complicates the internal design (we usually
+    // have to determine if two sections are mergeable early in the link
+    // process much before applying relocations). We simply handle mergeable
+    // sections with relocations as non-mergeable.
+    if (auto *MS = dyn_cast<MergeInputSection>(Target)) {
+      Target = toRegularSection(MS);
+      this->Sections[Sec.sh_info] = Target;
+    }
+
+    size_t NumRelocations;
+    if (Sec.sh_type == SHT_RELA) {
+      ArrayRef<Elf_Rela> Rels =
+          check(this->getObj().relas(&Sec), toString(this));
+      Target->FirstRelocation = Rels.begin();
+      NumRelocations = Rels.size();
+      Target->AreRelocsRela = true;
+    } else {
+      ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this));
+      Target->FirstRelocation = Rels.begin();
+      NumRelocations = Rels.size();
+      Target->AreRelocsRela = false;
+    }
+    assert(isUInt<31>(NumRelocations));
+    Target->NumRelocations = NumRelocations;
+
+    // Relocation sections processed by the linker are usually removed
+    // from the output, so returning `nullptr` for the normal case.
+    // However, if -emit-relocs is given, we need to leave them in the output.
+    // (Some post link analysis tools need this information.)
+    if (Config->EmitRelocs) {
+      InputSection *RelocSec = make<InputSection>(this, &Sec, Name);
+      // We will not emit relocation section if target was discarded.
+      Target->DependentSections.push_back(RelocSec);
+      return RelocSec;
+    }
+    return nullptr;
+  }
+  }
+
+  // The GNU linker uses .note.GNU-stack section as a marker indicating
+  // that the code in the object file does not expect that the stack is
+  // executable (in terms of NX bit). If all input files have the marker,
+  // the GNU linker adds a PT_GNU_STACK segment to tells the loader to
+  // make the stack non-executable. Most object files have this section as
+  // of 2017.
+  //
+  // But making the stack non-executable is a norm today for security
+  // reasons. Failure to do so may result in a serious security issue.
+  // Therefore, we make LLD always add PT_GNU_STACK unless it is
+  // explicitly told to do otherwise (by -z execstack). Because the stack
+  // executable-ness is controlled solely by command line options,
+  // .note.GNU-stack sections are simply ignored.
+  if (Name == ".note.GNU-stack")
+    return &InputSection::Discarded;
+
+  // Split stacks is a feature to support a discontiguous stack. At least
+  // as of 2017, it seems that the feature is not being used widely.
+  // Only GNU gold supports that. We don't. For the details about that,
+  // see https://gcc.gnu.org/wiki/SplitStacks
+  if (Name == ".note.GNU-split-stack") {
+    error(toString(this) +
+          ": object file compiled with -fsplit-stack is not supported");
+    return &InputSection::Discarded;
+  }
+
+  if (Config->Strip != StripPolicy::None && Name.startswith(".debug"))
+    return &InputSection::Discarded;
+
+  // If -gdb-index is given, LLD creates .gdb_index section, and that
+  // section serves the same purpose as .debug_gnu_pub{names,types} sections.
+  // If that's the case, we want to eliminate .debug_gnu_pub{names,types}
+  // because they are redundant and can waste large amount of disk space
+  // (for example, they are about 400 MiB in total for a clang debug build.)
+  if (Config->GdbIndex &&
+      (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes"))
+    return &InputSection::Discarded;
+
+  // The linkonce feature is a sort of proto-comdat. Some glibc i386 object
+  // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
+  // sections. Drop those sections to avoid duplicate symbol errors.
+  // FIXME: This is glibc PR20543, we should remove this hack once that has been
+  // fixed for a while.
+  if (Name.startswith(".gnu.linkonce."))
+    return &InputSection::Discarded;
+
+  // The linker merges EH (exception handling) frames and creates a
+  // .eh_frame_hdr section for runtime. So we handle them with a special
+  // class. For relocatable outputs, they are just passed through.
+  if (Name == ".eh_frame" && !Config->Relocatable)
+    return make<EhInputSection>(this, &Sec, Name);
+
+  if (shouldMerge(Sec))
+    return make<MergeInputSection>(this, &Sec, Name);
+  return make<InputSection>(this, &Sec, Name);
+}
+
+template <class ELFT>
+StringRef elf::ObjectFile<ELFT>::getSectionName(const Elf_Shdr &Sec) {
+  return check(this->getObj().getSectionName(&Sec, SectionStringTable),
+               toString(this));
+}
+
+template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
+  SymbolBodies.reserve(this->Symbols.size());
+  for (const Elf_Sym &Sym : this->Symbols)
+    SymbolBodies.push_back(createSymbolBody(&Sym));
+}
+
+template <class ELFT>
+InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
+  uint32_t Index = this->getSectionIndex(Sym);
+  if (Index >= this->Sections.size())
+    fatal(toString(this) + ": invalid section index: " + Twine(Index));
+  InputSectionBase *S = this->Sections[Index];
+
+  // We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could
+  // generate broken objects. STT_SECTION/STT_NOTYPE symbols can be
+  // associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections.
+  // In this case it is fine for section to be null here as we do not
+  // allocate sections of these types.
+  if (!S) {
+    if (Index == 0 || Sym.getType() == STT_SECTION ||
+        Sym.getType() == STT_NOTYPE)
+      return nullptr;
+    fatal(toString(this) + ": invalid section index: " + Twine(Index));
+  }
+
+  if (S == &InputSection::Discarded)
+    return S;
+  return S->Repl;
+}
+
+template <class ELFT>
+SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
+  int Binding = Sym->getBinding();
+  InputSectionBase *Sec = getSection(*Sym);
+
+  uint8_t StOther = Sym->st_other;
+  uint8_t Type = Sym->getType();
+  uint64_t Value = Sym->st_value;
+  uint64_t Size = Sym->st_size;
+
+  if (Binding == STB_LOCAL) {
+    if (Sym->getType() == STT_FILE)
+      SourceFile = check(Sym->getName(this->StringTable), toString(this));
+
+    if (this->StringTable.size() <= Sym->st_name)
+      fatal(toString(this) + ": invalid symbol name offset");
+
+    StringRefZ Name = this->StringTable.data() + Sym->st_name;
+    if (Sym->st_shndx == SHN_UNDEF)
+      return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this);
+
+    return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value,
+                                Size, Sec, this);
+  }
+
+  StringRef Name = check(Sym->getName(this->StringTable), toString(this));
+
+  switch (Sym->st_shndx) {
+  case SHN_UNDEF:
+    return elf::Symtab<ELFT>::X
+        ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
+                       /*CanOmitFromDynSym=*/false, this)
+        ->body();
+  case SHN_COMMON:
+    if (Value == 0 || Value >= UINT32_MAX)
+      fatal(toString(this) + ": common symbol '" + Name +
+            "' has invalid alignment: " + Twine(Value));
+    return elf::Symtab<ELFT>::X
+        ->addCommon(Name, Size, Value, Binding, StOther, Type, this)
+        ->body();
+  }
+
+  switch (Binding) {
+  default:
+    fatal(toString(this) + ": unexpected binding: " + Twine(Binding));
+  case STB_GLOBAL:
+  case STB_WEAK:
+  case STB_GNU_UNIQUE:
+    if (Sec == &InputSection::Discarded)
+      return elf::Symtab<ELFT>::X
+          ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
+                         /*CanOmitFromDynSym=*/false, this)
+          ->body();
+    return elf::Symtab<ELFT>::X
+        ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this)
+        ->body();
+  }
+}
+
+ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
+    : InputFile(ArchiveKind, File->getMemoryBufferRef()),
+      File(std::move(File)) {}
+
+template <class ELFT> void ArchiveFile::parse() {
+  Symbols.reserve(File->getNumberOfSymbols());
+  for (const Archive::Symbol &Sym : File->symbols())
+    Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym));
+}
+
+// Returns a buffer pointing to a member file containing a given symbol.
+std::pair<MemoryBufferRef, uint64_t>
+ArchiveFile::getMember(const Archive::Symbol *Sym) {
+  Archive::Child C =
+      check(Sym->getMember(), toString(this) +
+                                  ": could not get the member for symbol " +
+                                  Sym->getName());
+
+  if (!Seen.insert(C.getChildOffset()).second)
+    return {MemoryBufferRef(), 0};
+
+  MemoryBufferRef Ret =
+      check(C.getMemoryBufferRef(),
+            toString(this) +
+                ": could not get the buffer for the member defining symbol " +
+                Sym->getName());
+
+  if (C.getParent()->isThin() && Tar)
+    Tar->append(relativeToRoot(check(C.getFullName(), toString(this))),
+                Ret.getBuffer());
+  if (C.getParent()->isThin())
+    return {Ret, 0};
+  return {Ret, C.getChildOffset()};
+}
+
+template <class ELFT>
+SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
+    : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName),
+      AsNeeded(Config->AsNeeded) {}
+
+template <class ELFT>
+const typename ELFT::Shdr *
+SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
+  return check(
+      this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX),
+      toString(this));
+}
+
+// Partially parse the shared object file so that we can call
+// getSoName on this object.
+template <class ELFT> void SharedFile<ELFT>::parseSoName() {
+  const Elf_Shdr *DynamicSec = nullptr;
+  const ELFFile<ELFT> Obj = this->getObj();
+  ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
+
+  // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
+  for (const Elf_Shdr &Sec : Sections) {
+    switch (Sec.sh_type) {
+    default:
+      continue;
+    case SHT_DYNSYM:
+      this->initSymtab(Sections, &Sec);
+      break;
+    case SHT_DYNAMIC:
+      DynamicSec = &Sec;
+      break;
+    case SHT_SYMTAB_SHNDX:
+      this->SymtabSHNDX =
+          check(Obj.getSHNDXTable(Sec, Sections), toString(this));
+      break;
+    case SHT_GNU_versym:
+      this->VersymSec = &Sec;
+      break;
+    case SHT_GNU_verdef:
+      this->VerdefSec = &Sec;
+      break;
+    }
+  }
+
+  if (this->VersymSec && this->Symbols.empty())
+    error("SHT_GNU_versym should be associated with symbol table");
+
+  // Search for a DT_SONAME tag to initialize this->SoName.
+  if (!DynamicSec)
+    return;
+  ArrayRef<Elf_Dyn> Arr =
+      check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec),
+            toString(this));
+  for (const Elf_Dyn &Dyn : Arr) {
+    if (Dyn.d_tag == DT_SONAME) {
+      uint64_t Val = Dyn.getVal();
+      if (Val >= this->StringTable.size())
+        fatal(toString(this) + ": invalid DT_SONAME entry");
+      SoName = this->StringTable.data() + Val;
+      return;
+    }
+  }
+}
+
+// Parse the version definitions in the object file if present. Returns a vector
+// whose nth element contains a pointer to the Elf_Verdef for version identifier
+// n. Version identifiers that are not definitions map to nullptr. The array
+// always has at least length 1.
+template <class ELFT>
+std::vector<const typename ELFT::Verdef *>
+SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
+  std::vector<const Elf_Verdef *> Verdefs(1);
+  // We only need to process symbol versions for this DSO if it has both a
+  // versym and a verdef section, which indicates that the DSO contains symbol
+  // version definitions.
+  if (!VersymSec || !VerdefSec)
+    return Verdefs;
+
+  // The location of the first global versym entry.
+  const char *Base = this->MB.getBuffer().data();
+  Versym = reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
+           this->FirstNonLocal;
+
+  // We cannot determine the largest verdef identifier without inspecting
+  // every Elf_Verdef, but both bfd and gold assign verdef identifiers
+  // sequentially starting from 1, so we predict that the largest identifier
+  // will be VerdefCount.
+  unsigned VerdefCount = VerdefSec->sh_info;
+  Verdefs.resize(VerdefCount + 1);
+
+  // Build the Verdefs array by following the chain of Elf_Verdef objects
+  // from the start of the .gnu.version_d section.
+  const char *Verdef = Base + VerdefSec->sh_offset;
+  for (unsigned I = 0; I != VerdefCount; ++I) {
+    auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
+    Verdef += CurVerdef->vd_next;
+    unsigned VerdefIndex = CurVerdef->vd_ndx;
+    if (Verdefs.size() <= VerdefIndex)
+      Verdefs.resize(VerdefIndex + 1);
+    Verdefs[VerdefIndex] = CurVerdef;
+  }
+
+  return Verdefs;
+}
+
+// Fully parse the shared object file. This must be called after parseSoName().
+template <class ELFT> void SharedFile<ELFT>::parseRest() {
+  // Create mapping from version identifiers to Elf_Verdef entries.
+  const Elf_Versym *Versym = nullptr;
+  std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
+
+  Elf_Sym_Range Syms = this->getGlobalSymbols();
+  for (const Elf_Sym &Sym : Syms) {
+    unsigned VersymIndex = 0;
+    if (Versym) {
+      VersymIndex = Versym->vs_index;
+      ++Versym;
+    }
+    bool Hidden = VersymIndex & VERSYM_HIDDEN;
+    VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
+
+    StringRef Name = check(Sym.getName(this->StringTable), toString(this));
+    if (Sym.isUndefined()) {
+      Undefs.push_back(Name);
+      continue;
+    }
+
+    // Ignore local symbols.
+    if (Versym && VersymIndex == VER_NDX_LOCAL)
+      continue;
+
+    const Elf_Verdef *V =
+        VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex];
+
+    if (!Hidden)
+      elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+
+    // Also add the symbol with the versioned name to handle undefined symbols
+    // with explicit versions.
+    if (V) {
+      StringRef VerName = this->StringTable.data() + V->getAux()->vda_name;
+      Name = Saver.save(Name + "@" + VerName);
+      elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+    }
+  }
+}
+
+static ELFKind getBitcodeELFKind(const Triple &T) {
+  if (T.isLittleEndian())
+    return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
+  return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
+}
+
+static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
+  switch (T.getArch()) {
+  case Triple::aarch64:
+    return EM_AARCH64;
+  case Triple::arm:
+  case Triple::thumb:
+    return EM_ARM;
+  case Triple::avr:
+    return EM_AVR;
+  case Triple::mips:
+  case Triple::mipsel:
+  case Triple::mips64:
+  case Triple::mips64el:
+    return EM_MIPS;
+  case Triple::ppc:
+    return EM_PPC;
+  case Triple::ppc64:
+    return EM_PPC64;
+  case Triple::x86:
+    return T.isOSIAMCU() ? EM_IAMCU : EM_386;
+  case Triple::x86_64:
+    return EM_X86_64;
+  default:
+    fatal(Path + ": could not infer e_machine from bitcode target triple " +
+          T.str());
+  }
+}
+
+BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
+                         uint64_t OffsetInArchive)
+    : InputFile(BitcodeKind, MB) {
+  this->ArchiveName = ArchiveName;
+
+  // Here we pass a new MemoryBufferRef which is identified by ArchiveName
+  // (the fully resolved path of the archive) + member name + offset of the
+  // member in the archive.
+  // ThinLTO uses the MemoryBufferRef identifier to access its internal
+  // data structures and if two archives define two members with the same name,
+  // this causes a collision which result in only one of the objects being
+  // taken into consideration at LTO time (which very likely causes undefined
+  // symbols later in the link stage).
+  MemoryBufferRef MBRef(MB.getBuffer(),
+                        Saver.save(ArchiveName + MB.getBufferIdentifier() +
+                                   utostr(OffsetInArchive)));
+  Obj = check(lto::InputFile::create(MBRef), toString(this));
+
+  Triple T(Obj->getTargetTriple());
+  EKind = getBitcodeELFKind(T);
+  EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T);
+}
+
+static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
+  switch (GvVisibility) {
+  case GlobalValue::DefaultVisibility:
+    return STV_DEFAULT;
+  case GlobalValue::HiddenVisibility:
+    return STV_HIDDEN;
+  case GlobalValue::ProtectedVisibility:
+    return STV_PROTECTED;
+  }
+  llvm_unreachable("unknown visibility");
+}
+
+template <class ELFT>
+static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
+                                   const lto::InputFile::Symbol &ObjSym,
+                                   BitcodeFile *F) {
+  StringRef NameRef = Saver.save(ObjSym.getName());
+  uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
+
+  uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
+  uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
+  bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
+
+  int C = ObjSym.getComdatIndex();
+  if (C != -1 && !KeptComdats[C])
+    return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
+                                         Visibility, Type, CanOmitFromDynSym,
+                                         F);
+
+  if (ObjSym.isUndefined())
+    return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
+                                         Visibility, Type, CanOmitFromDynSym,
+                                         F);
+
+  if (ObjSym.isCommon())
+    return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
+                                      ObjSym.getCommonAlignment(), Binding,
+                                      Visibility, STT_OBJECT, F);
+
+  return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type,
+                                     CanOmitFromDynSym, F);
+}
+
+template <class ELFT>
+void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+  std::vector<bool> KeptComdats;
+  for (StringRef S : Obj->getComdatTable())
+    KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
+
+  for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
+    Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
+}
+
+static ELFKind getELFKind(MemoryBufferRef MB) {
+  unsigned char Size;
+  unsigned char Endian;
+  std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
+
+  if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
+    fatal(MB.getBufferIdentifier() + ": invalid data encoding");
+  if (Size != ELFCLASS32 && Size != ELFCLASS64)
+    fatal(MB.getBufferIdentifier() + ": invalid file class");
+
+  size_t BufSize = MB.getBuffer().size();
+  if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) ||
+      (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr)))
+    fatal(MB.getBufferIdentifier() + ": file is too short");
+
+  if (Size == ELFCLASS32)
+    return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind;
+  return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind;
+}
+
+template <class ELFT> void BinaryFile::parse() {
+  ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
+  auto *Section =
+      make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data");
+  Sections.push_back(Section);
+
+  // For each input file foo that is embedded to a result as a binary
+  // blob, we define _binary_foo_{start,end,size} symbols, so that
+  // user programs can access blobs by name. Non-alphanumeric
+  // characters in a filename are replaced with underscore.
+  std::string S = "_binary_" + MB.getBufferIdentifier().str();
+  for (size_t I = 0; I < S.size(); ++I)
+    if (!isalnum(S[I]))
+      S[I] = '_';
+
+  elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT,
+                                   STT_OBJECT, 0, 0, STB_GLOBAL, Section,
+                                   nullptr);
+  elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT,
+                                   STT_OBJECT, Data.size(), 0, STB_GLOBAL,
+                                   Section, nullptr);
+  elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT,
+                                   STT_OBJECT, Data.size(), 0, STB_GLOBAL,
+                                   nullptr, nullptr);
+}
+
+static bool isBitcode(MemoryBufferRef MB) {
+  using namespace sys::fs;
+  return identify_magic(MB.getBuffer()) == file_magic::bitcode;
+}
+
+InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
+                                 uint64_t OffsetInArchive) {
+  if (isBitcode(MB))
+    return make<BitcodeFile>(MB, ArchiveName, OffsetInArchive);
+
+  switch (getELFKind(MB)) {
+  case ELF32LEKind:
+    return make<ObjectFile<ELF32LE>>(MB, ArchiveName);
+  case ELF32BEKind:
+    return make<ObjectFile<ELF32BE>>(MB, ArchiveName);
+  case ELF64LEKind:
+    return make<ObjectFile<ELF64LE>>(MB, ArchiveName);
+  case ELF64BEKind:
+    return make<ObjectFile<ELF64BE>>(MB, ArchiveName);
+  default:
+    llvm_unreachable("getELFKind");
+  }
+}
+
+InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
+  switch (getELFKind(MB)) {
+  case ELF32LEKind:
+    return make<SharedFile<ELF32LE>>(MB, DefaultSoName);
+  case ELF32BEKind:
+    return make<SharedFile<ELF32BE>>(MB, DefaultSoName);
+  case ELF64LEKind:
+    return make<SharedFile<ELF64LE>>(MB, DefaultSoName);
+  case ELF64BEKind:
+    return make<SharedFile<ELF64BE>>(MB, DefaultSoName);
+  default:
+    llvm_unreachable("getELFKind");
+  }
+}
+
+MemoryBufferRef LazyObjectFile::getBuffer() {
+  if (Seen)
+    return MemoryBufferRef();
+  Seen = true;
+  return MB;
+}
+
+InputFile *LazyObjectFile::fetch() {
+  MemoryBufferRef MBRef = getBuffer();
+  if (MBRef.getBuffer().empty())
+    return nullptr;
+  return createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+}
+
+template <class ELFT> void LazyObjectFile::parse() {
+  for (StringRef Sym : getSymbols())
+    Symtab<ELFT>::X->addLazyObject(Sym, *this);
+}
+
+template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+
+  const ELFFile<ELFT> Obj(this->MB.getBuffer());
+  ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
+  for (const Elf_Shdr &Sec : Sections) {
+    if (Sec.sh_type != SHT_SYMTAB)
+      continue;
+
+    Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this));
+    uint32_t FirstNonLocal = Sec.sh_info;
+    StringRef StringTable =
+        check(Obj.getStringTableForSymtab(Sec, Sections), toString(this));
+    std::vector<StringRef> V;
+
+    for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
+      if (Sym.st_shndx != SHN_UNDEF)
+        V.push_back(check(Sym.getName(StringTable), toString(this)));
+    return V;
+  }
+  return {};
+}
+
+std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
+  std::unique_ptr<lto::InputFile> Obj =
+      check(lto::InputFile::create(this->MB), toString(this));
+  std::vector<StringRef> V;
+  for (const lto::InputFile::Symbol &Sym : Obj->symbols())
+    if (!Sym.isUndefined())
+      V.push_back(Saver.save(Sym.getName()));
+  return V;
+}
+
+// Returns a vector of globally-visible defined symbol names.
+std::vector<StringRef> LazyObjectFile::getSymbols() {
+  if (isBitcode(this->MB))
+    return getBitcodeSymbols();
+
+  switch (getELFKind(this->MB)) {
+  case ELF32LEKind:
+    return getElfSymbols<ELF32LE>();
+  case ELF32BEKind:
+    return getElfSymbols<ELF32BE>();
+  case ELF64LEKind:
+    return getElfSymbols<ELF64LE>();
+  case ELF64BEKind:
+    return getElfSymbols<ELF64BE>();
+  default:
+    llvm_unreachable("getELFKind");
+  }
+}
+
+template void ArchiveFile::parse<ELF32LE>();
+template void ArchiveFile::parse<ELF32BE>();
+template void ArchiveFile::parse<ELF64LE>();
+template void ArchiveFile::parse<ELF64BE>();
+
+template void BitcodeFile::parse<ELF32LE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &);
+
+template void LazyObjectFile::parse<ELF32LE>();
+template void LazyObjectFile::parse<ELF32BE>();
+template void LazyObjectFile::parse<ELF64LE>();
+template void LazyObjectFile::parse<ELF64BE>();
+
+template class elf::ELFFileBase<ELF32LE>;
+template class elf::ELFFileBase<ELF32BE>;
+template class elf::ELFFileBase<ELF64LE>;
+template class elf::ELFFileBase<ELF64BE>;
+
+template class elf::ObjectFile<ELF32LE>;
+template class elf::ObjectFile<ELF32BE>;
+template class elf::ObjectFile<ELF64LE>;
+template class elf::ObjectFile<ELF64BE>;
+
+template class elf::SharedFile<ELF32LE>;
+template class elf::SharedFile<ELF32BE>;
+template class elf::SharedFile<ELF64LE>;
+template class elf::SharedFile<ELF64BE>;
+
+template void BinaryFile::parse<ELF32LE>();
+template void BinaryFile::parse<ELF32BE>();
+template void BinaryFile::parse<ELF64LE>();
+template void BinaryFile::parse<ELF64BE>();
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
new file mode 100644 (file)
index 0000000..006218b
--- /dev/null
@@ -0,0 +1,346 @@
+//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_INPUT_FILES_H
+#define LLD_ELF_INPUT_FILES_H
+
+#include "Config.h"
+#include "Error.h"
+#include "InputSection.h"
+#include "Symbols.h"
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reproduce.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Comdat.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/Threading.h"
+
+#include <map>
+
+namespace llvm {
+class DWARFDebugLine;
+class TarWriter;
+struct DILineInfo;
+namespace lto {
+class InputFile;
+}
+} // namespace llvm
+
+namespace lld {
+namespace elf {
+class InputFile;
+}
+
+// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+std::string toString(const elf::InputFile *F);
+
+namespace elf {
+
+using llvm::object::Archive;
+
+class Lazy;
+class SymbolBody;
+
+// If -reproduce option is given, all input files are written
+// to this tar archive.
+extern llvm::TarWriter *Tar;
+
+// Opens a given file.
+llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
+
+// The root class of input files.
+class InputFile {
+public:
+  enum Kind {
+    ObjectKind,
+    SharedKind,
+    LazyObjectKind,
+    ArchiveKind,
+    BitcodeKind,
+    BinaryKind,
+  };
+
+  Kind kind() const { return FileKind; }
+
+  StringRef getName() const { return MB.getBufferIdentifier(); }
+  MemoryBufferRef MB;
+
+  // Returns sections. It is a runtime error to call this function
+  // on files that don't have the notion of sections.
+  ArrayRef<InputSectionBase *> getSections() const {
+    assert(FileKind == ObjectKind || FileKind == BinaryKind);
+    return Sections;
+  }
+
+  // Filename of .a which contained this file. If this file was
+  // not in an archive file, it is the empty string. We use this
+  // string for creating error messages.
+  StringRef ArchiveName;
+
+  // If this is an architecture-specific file, the following members
+  // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
+  ELFKind EKind = ELFNoneKind;
+  uint16_t EMachine = llvm::ELF::EM_NONE;
+  uint8_t OSABI = 0;
+
+  // Cache for toString(). Only toString() should use this member.
+  mutable std::string ToStringCache;
+
+protected:
+  InputFile(Kind K, MemoryBufferRef M);
+  std::vector<InputSectionBase *> Sections;
+
+private:
+  const Kind FileKind;
+};
+
+template <typename ELFT> class ELFFileBase : public InputFile {
+public:
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Word Elf_Word;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+
+  ELFFileBase(Kind K, MemoryBufferRef M);
+  static bool classof(const InputFile *F) {
+    Kind K = F->kind();
+    return K == ObjectKind || K == SharedKind;
+  }
+
+  llvm::object::ELFFile<ELFT> getObj() const {
+    return llvm::object::ELFFile<ELFT>(MB.getBuffer());
+  }
+
+  StringRef getStringTable() const { return StringTable; }
+
+  uint32_t getSectionIndex(const Elf_Sym &Sym) const;
+
+  Elf_Sym_Range getGlobalSymbols();
+
+protected:
+  ArrayRef<Elf_Sym> Symbols;
+  uint32_t FirstNonLocal = 0;
+  ArrayRef<Elf_Word> SymtabSHNDX;
+  StringRef StringTable;
+  void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab);
+};
+
+// .o file.
+template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
+  typedef ELFFileBase<ELFT> Base;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Word Elf_Word;
+
+  StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
+                                 const Elf_Shdr &Sec);
+  ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec);
+
+public:
+  static bool classof(const InputFile *F) {
+    return F->kind() == Base::ObjectKind;
+  }
+
+  ArrayRef<SymbolBody *> getSymbols();
+  ArrayRef<SymbolBody *> getLocalSymbols();
+
+  ObjectFile(MemoryBufferRef M, StringRef ArchiveName);
+  void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+
+  InputSectionBase *getSection(const Elf_Sym &Sym) const;
+
+  SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
+    if (SymbolIndex >= SymbolBodies.size())
+      fatal(toString(this) + ": invalid symbol index");
+    return *SymbolBodies[SymbolIndex];
+  }
+
+  template <typename RelT>
+  SymbolBody &getRelocTargetSym(const RelT &Rel) const {
+    uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
+    return getSymbolBody(SymIndex);
+  }
+
+  // Returns source line information for a given offset.
+  // If no information is available, returns "".
+  std::string getLineInfo(InputSectionBase *S, uint64_t Offset);
+  llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
+
+  // MIPS GP0 value defined by this file. This value represents the gp value
+  // used to create the relocatable object and required to support
+  // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
+  uint32_t MipsGp0 = 0;
+
+  // Name of source file obtained from STT_FILE symbol value,
+  // or empty string if there is no such symbol in object file
+  // symbol table.
+  StringRef SourceFile;
+
+private:
+  void
+  initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+  void initializeSymbols();
+  void initializeDwarfLine();
+  InputSectionBase *getRelocTarget(const Elf_Shdr &Sec);
+  InputSectionBase *createInputSection(const Elf_Shdr &Sec);
+  StringRef getSectionName(const Elf_Shdr &Sec);
+
+  bool shouldMerge(const Elf_Shdr &Sec);
+  SymbolBody *createSymbolBody(const Elf_Sym *Sym);
+
+  // List of all symbols referenced or defined by this file.
+  std::vector<SymbolBody *> SymbolBodies;
+
+  // .shstrtab contents.
+  StringRef SectionStringTable;
+
+  // Debugging information to retrieve source file and line for error
+  // reporting. Linker may find reasonable number of errors in a
+  // single object file, so we cache debugging information in order to
+  // parse it only once for each object file we link.
+  std::unique_ptr<llvm::DWARFDebugLine> DwarfLine;
+  llvm::once_flag InitDwarfLine;
+};
+
+// LazyObjectFile is analogous to ArchiveFile in the sense that
+// the file contains lazy symbols. The difference is that
+// LazyObjectFile wraps a single file instead of multiple files.
+//
+// This class is used for --start-lib and --end-lib options which
+// instruct the linker to link object files between them with the
+// archive file semantics.
+class LazyObjectFile : public InputFile {
+public:
+  LazyObjectFile(MemoryBufferRef M, StringRef ArchiveName,
+                 uint64_t OffsetInArchive)
+      : InputFile(LazyObjectKind, M), OffsetInArchive(OffsetInArchive) {
+    this->ArchiveName = ArchiveName;
+  }
+
+  static bool classof(const InputFile *F) {
+    return F->kind() == LazyObjectKind;
+  }
+
+  template <class ELFT> void parse();
+  MemoryBufferRef getBuffer();
+  InputFile *fetch();
+
+private:
+  std::vector<StringRef> getSymbols();
+  template <class ELFT> std::vector<StringRef> getElfSymbols();
+  std::vector<StringRef> getBitcodeSymbols();
+
+  bool Seen = false;
+  uint64_t OffsetInArchive;
+};
+
+// An ArchiveFile object represents a .a file.
+class ArchiveFile : public InputFile {
+public:
+  explicit ArchiveFile(std::unique_ptr<Archive> &&File);
+  static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+  template <class ELFT> void parse();
+  ArrayRef<Symbol *> getSymbols() { return Symbols; }
+
+  // Returns a memory buffer for a given symbol and the offset in the archive
+  // for the member. An empty memory buffer and an offset of zero
+  // is returned if we have already returned the same memory buffer.
+  // (So that we don't instantiate same members more than once.)
+  std::pair<MemoryBufferRef, uint64_t> getMember(const Archive::Symbol *Sym);
+
+private:
+  std::unique_ptr<Archive> File;
+  llvm::DenseSet<uint64_t> Seen;
+  std::vector<Symbol *> Symbols;
+};
+
+class BitcodeFile : public InputFile {
+public:
+  BitcodeFile(MemoryBufferRef M, StringRef ArchiveName,
+              uint64_t OffsetInArchive);
+  static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+  template <class ELFT>
+  void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+  ArrayRef<Symbol *> getSymbols() { return Symbols; }
+  std::unique_ptr<llvm::lto::InputFile> Obj;
+
+private:
+  std::vector<Symbol *> Symbols;
+};
+
+// .so file.
+template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
+  typedef ELFFileBase<ELFT> Base;
+  typedef typename ELFT::Dyn Elf_Dyn;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+  typedef typename ELFT::Verdef Elf_Verdef;
+  typedef typename ELFT::Versym Elf_Versym;
+
+  std::vector<StringRef> Undefs;
+  const Elf_Shdr *VersymSec = nullptr;
+  const Elf_Shdr *VerdefSec = nullptr;
+
+public:
+  std::string SoName;
+
+  const Elf_Shdr *getSection(const Elf_Sym &Sym) const;
+  llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
+
+  static bool classof(const InputFile *F) {
+    return F->kind() == Base::SharedKind;
+  }
+
+  SharedFile(MemoryBufferRef M, StringRef DefaultSoName);
+
+  void parseSoName();
+  void parseRest();
+  std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym);
+
+  struct NeededVer {
+    // The string table offset of the version name in the output file.
+    size_t StrTab;
+
+    // The version identifier for this version name.
+    uint16_t Index;
+  };
+
+  // Mapping from Elf_Verdef data structures to information about Elf_Vernaux
+  // data structures in the output file.
+  std::map<const Elf_Verdef *, NeededVer> VerdefMap;
+
+  // Used for --as-needed
+  bool AsNeeded = false;
+  bool IsUsed = false;
+  bool isNeeded() const { return !AsNeeded || IsUsed; }
+};
+
+class BinaryFile : public InputFile {
+public:
+  explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == BinaryKind; }
+  template <class ELFT> void parse();
+};
+
+InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
+                            uint64_t OffsetInArchive = 0);
+InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
new file mode 100644 (file)
index 0000000..c6a539b
--- /dev/null
@@ -0,0 +1,1040 @@
+//===- InputSection.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputSection.h"
+#include "Config.h"
+#include "EhFrame.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Relocations.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "llvm/Object/Decompressor.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Threading.h"
+#include <mutex>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+using namespace llvm::sys;
+
+using namespace lld;
+using namespace lld::elf;
+
+std::vector<InputSectionBase *> elf::InputSections;
+
+// Returns a string to construct an error message.
+std::string lld::toString(const InputSectionBase *Sec) {
+  return (toString(Sec->File) + ":(" + Sec->Name + ")").str();
+}
+
+template <class ELFT>
+static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File,
+                                            const typename ELFT::Shdr *Hdr) {
+  if (!File || Hdr->sh_type == SHT_NOBITS)
+    return makeArrayRef<uint8_t>(nullptr, Hdr->sh_size);
+  return check(File->getObj().getSectionContents(Hdr));
+}
+
+InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
+                                   uint32_t Type, uint64_t Entsize,
+                                   uint32_t Link, uint32_t Info,
+                                   uint32_t Alignment, ArrayRef<uint8_t> Data,
+                                   StringRef Name, Kind SectionKind)
+    : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info,
+                  Link),
+      File(File), Data(Data), Repl(this) {
+  Live = !Config->GcSections || !(Flags & SHF_ALLOC);
+  Assigned = false;
+  NumRelocations = 0;
+  AreRelocsRela = false;
+
+  // The ELF spec states that a value of 0 means the section has
+  // no alignment constraits.
+  uint32_t V = std::max<uint64_t>(Alignment, 1);
+  if (!isPowerOf2_64(V))
+    fatal(toString(File) + ": section sh_addralign is not a power of 2");
+  this->Alignment = V;
+}
+
+// Drop SHF_GROUP bit unless we are producing a re-linkable object file.
+// SHF_GROUP is a marker that a section belongs to some comdat group.
+// That flag doesn't make sense in an executable.
+static uint64_t getFlags(uint64_t Flags) {
+  Flags &= ~(uint64_t)SHF_INFO_LINK;
+  if (!Config->Relocatable)
+    Flags &= ~(uint64_t)SHF_GROUP;
+  return Flags;
+}
+
+// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of
+// March 2017) fail to infer section types for sections starting with
+// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of
+// SHF_INIT_ARRAY. As a result, the following assembler directive
+// creates ".init_array.100" with SHT_PROGBITS, for example.
+//
+//   .section .init_array.100, "aw"
+//
+// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle
+// incorrect inputs as if they were correct from the beginning.
+static uint64_t getType(uint64_t Type, StringRef Name) {
+  if (Type == SHT_PROGBITS && Name.startswith(".init_array."))
+    return SHT_INIT_ARRAY;
+  if (Type == SHT_PROGBITS && Name.startswith(".fini_array."))
+    return SHT_FINI_ARRAY;
+  return Type;
+}
+
+template <class ELFT>
+InputSectionBase::InputSectionBase(elf::ObjectFile<ELFT> *File,
+                                   const typename ELFT::Shdr *Hdr,
+                                   StringRef Name, Kind SectionKind)
+    : InputSectionBase(File, getFlags(Hdr->sh_flags),
+                       getType(Hdr->sh_type, Name), Hdr->sh_entsize,
+                       Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign,
+                       getSectionContents(File, Hdr), Name, SectionKind) {
+  // We reject object files having insanely large alignments even though
+  // they are allowed by the spec. I think 4GB is a reasonable limitation.
+  // We might want to relax this in the future.
+  if (Hdr->sh_addralign > UINT32_MAX)
+    fatal(toString(File) + ": section sh_addralign is too large");
+}
+
+size_t InputSectionBase::getSize() const {
+  if (auto *S = dyn_cast<SyntheticSection>(this))
+    return S->getSize();
+
+  return Data.size();
+}
+
+uint64_t InputSectionBase::getOffsetInFile() const {
+  const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart();
+  const uint8_t *SecStart = Data.begin();
+  return SecStart - FileStart;
+}
+
+uint64_t SectionBase::getOffset(uint64_t Offset) const {
+  switch (kind()) {
+  case Output: {
+    auto *OS = cast<OutputSection>(this);
+    // For output sections we treat offset -1 as the end of the section.
+    return Offset == uint64_t(-1) ? OS->Size : Offset;
+  }
+  case Regular:
+    return cast<InputSection>(this)->OutSecOff + Offset;
+  case Synthetic: {
+    auto *IS = cast<InputSection>(this);
+    // For synthetic sections we treat offset -1 as the end of the section.
+    return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset);
+  }
+  case EHFrame:
+    // The file crtbeginT.o has relocations pointing to the start of an empty
+    // .eh_frame that is known to be the first in the link. It does that to
+    // identify the start of the output .eh_frame.
+    return Offset;
+  case Merge:
+    const MergeInputSection *MS = cast<MergeInputSection>(this);
+    if (InputSection *IS = MS->getParent())
+      return IS->OutSecOff + MS->getOffset(Offset);
+    return MS->getOffset(Offset);
+  }
+  llvm_unreachable("invalid section kind");
+}
+
+OutputSection *SectionBase::getOutputSection() {
+  InputSection *Sec;
+  if (auto *IS = dyn_cast<InputSection>(this))
+    Sec = IS;
+  else if (auto *MS = dyn_cast<MergeInputSection>(this))
+    Sec = MS->getParent();
+  else if (auto *EH = dyn_cast<EhInputSection>(this))
+    Sec = EH->getParent();
+  else
+    return cast<OutputSection>(this);
+  return Sec ? Sec->getParent() : nullptr;
+}
+
+// Uncompress section contents. Note that this function is called
+// from parallel_for_each, so it must be thread-safe.
+void InputSectionBase::uncompress() {
+  Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data),
+                                                Config->IsLE, Config->Is64));
+
+  size_t Size = Dec.getDecompressedSize();
+  char *OutputBuf;
+  {
+    static std::mutex Mu;
+    std::lock_guard<std::mutex> Lock(Mu);
+    OutputBuf = BAlloc.Allocate<char>(Size);
+  }
+
+  if (Error E = Dec.decompress({OutputBuf, Size}))
+    fatal(toString(this) +
+          ": decompress failed: " + llvm::toString(std::move(E)));
+  this->Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
+  this->Flags &= ~(uint64_t)SHF_COMPRESSED;
+}
+
+uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const {
+  return getOffset(Sym.Value);
+}
+
+InputSection *InputSectionBase::getLinkOrderDep() const {
+  if ((Flags & SHF_LINK_ORDER) && Link != 0) {
+    InputSectionBase *L = File->getSections()[Link];
+    if (auto *IS = dyn_cast<InputSection>(L))
+      return IS;
+    error(
+        "Merge and .eh_frame sections are not supported with SHF_LINK_ORDER " +
+        toString(L));
+  }
+  return nullptr;
+}
+
+// Returns a source location string. Used to construct an error message.
+template <class ELFT>
+std::string InputSectionBase::getLocation(uint64_t Offset) {
+  // We don't have file for synthetic sections.
+  if (getFile<ELFT>() == nullptr)
+    return (Config->OutputFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")")
+        .str();
+
+  // First check if we can get desired values from debugging information.
+  std::string LineInfo = getFile<ELFT>()->getLineInfo(this, Offset);
+  if (!LineInfo.empty())
+    return LineInfo;
+
+  // File->SourceFile contains STT_FILE symbol that contains a
+  // source file name. If it's missing, we use an object file name.
+  std::string SrcFile = getFile<ELFT>()->SourceFile;
+  if (SrcFile.empty())
+    SrcFile = toString(File);
+
+  // Find a function symbol that encloses a given location.
+  for (SymbolBody *B : getFile<ELFT>()->getSymbols())
+    if (auto *D = dyn_cast<DefinedRegular>(B))
+      if (D->Section == this && D->Type == STT_FUNC)
+        if (D->Value <= Offset && Offset < D->Value + D->Size)
+          return SrcFile + ":(function " + toString(*D) + ")";
+
+  // If there's no symbol, print out the offset in the section.
+  return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
+}
+
+// Returns a source location string. This function is intended to be
+// used for constructing an error message. The returned message looks
+// like this:
+//
+//   foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42)
+//
+// Returns an empty string if there's no way to get line info.
+template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) {
+  // Synthetic sections don't have input files.
+  elf::ObjectFile<ELFT> *File = getFile<ELFT>();
+  if (!File)
+    return "";
+
+  Optional<DILineInfo> Info = File->getDILineInfo(this, Offset);
+
+  // File->SourceFile contains STT_FILE symbol, and that is a last resort.
+  if (!Info)
+    return File->SourceFile;
+
+  std::string Path = Info->FileName;
+  std::string Filename = path::filename(Path);
+  std::string Lineno = ":" + std::to_string(Info->Line);
+  if (Filename == Path)
+    return Filename + Lineno;
+  return Filename + Lineno + " (" + Path + Lineno + ")";
+}
+
+// Returns a filename string along with an optional section name. This
+// function is intended to be used for constructing an error
+// message. The returned message looks like this:
+//
+//   path/to/foo.o:(function bar)
+//
+// or
+//
+//   path/to/foo.o:(function bar) in archive path/to/bar.a
+template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) {
+  // Synthetic sections don't have input files.
+  elf::ObjectFile<ELFT> *File = getFile<ELFT>();
+  if (!File)
+    return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str();
+  std::string Filename = File->getName();
+
+  std::string Archive;
+  if (!File->ArchiveName.empty())
+    Archive = (" in archive " + File->ArchiveName).str();
+
+  // Find a symbol that encloses a given location.
+  for (SymbolBody *B : getFile<ELFT>()->getSymbols())
+    if (auto *D = dyn_cast<DefinedRegular>(B))
+      if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size)
+        return Filename + ":(" + toString(*D) + ")" + Archive;
+
+  // If there's no symbol, print out the offset in the section.
+  return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive)
+      .str();
+}
+
+InputSectionBase InputSectionBase::Discarded;
+
+InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+                           ArrayRef<uint8_t> Data, StringRef Name, Kind K)
+    : InputSectionBase(nullptr, Flags, Type,
+                       /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data,
+                       Name, K) {}
+
+template <class ELFT>
+InputSection::InputSection(elf::ObjectFile<ELFT> *F,
+                           const typename ELFT::Shdr *Header, StringRef Name)
+    : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {}
+
+bool InputSection::classof(const SectionBase *S) {
+  return S->kind() == SectionBase::Regular ||
+         S->kind() == SectionBase::Synthetic;
+}
+
+bool InputSectionBase::classof(const SectionBase *S) {
+  return S->kind() != Output;
+}
+
+OutputSection *InputSection::getParent() const {
+  return cast_or_null<OutputSection>(Parent);
+}
+
+// Copy SHT_GROUP section contents. Used only for the -r option.
+template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) {
+  // ELFT::Word is the 32-bit integral type in the target endianness.
+  typedef typename ELFT::Word u32;
+  ArrayRef<u32> From = getDataAs<u32>();
+  auto *To = reinterpret_cast<u32 *>(Buf);
+
+  // The first entry is not a section number but a flag.
+  *To++ = From[0];
+
+  // Adjust section numbers because section numbers in an input object
+  // files are different in the output.
+  ArrayRef<InputSectionBase *> Sections = this->File->getSections();
+  for (uint32_t Idx : From.slice(1))
+    *To++ = Sections[Idx]->getOutputSection()->SectionIndex;
+}
+
+InputSectionBase *InputSection::getRelocatedSection() {
+  assert(this->Type == SHT_RELA || this->Type == SHT_REL);
+  ArrayRef<InputSectionBase *> Sections = this->File->getSections();
+  return Sections[this->Info];
+}
+
+// This is used for -r and --emit-relocs. We can't use memcpy to copy
+// relocations because we need to update symbol table offset and section index
+// for each relocation. So we copy relocations one by one.
+template <class ELFT, class RelTy>
+void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+  InputSectionBase *RelocatedSection = getRelocatedSection();
+
+  // Loop is slow and have complexity O(N*M), where N - amount of
+  // relocations and M - amount of symbols in symbol table.
+  // That happens because getSymbolIndex(...) call below performs
+  // simple linear search.
+  for (const RelTy &Rel : Rels) {
+    uint32_t Type = Rel.getType(Config->IsMips64EL);
+    SymbolBody &Body = this->getFile<ELFT>()->getRelocTargetSym(Rel);
+
+    auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf);
+    Buf += sizeof(RelTy);
+
+    if (Config->IsRela)
+      P->r_addend = getAddend<ELFT>(Rel);
+
+    // Output section VA is zero for -r, so r_offset is an offset within the
+    // section, but for --emit-relocs it is an virtual address.
+    P->r_offset = RelocatedSection->getOutputSection()->Addr +
+                  RelocatedSection->getOffset(Rel.r_offset);
+    P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type,
+                        Config->IsMips64EL);
+
+    if (Body.Type == STT_SECTION) {
+      // We combine multiple section symbols into only one per
+      // section. This means we have to update the addend. That is
+      // trivial for Elf_Rela, but for Elf_Rel we have to write to the
+      // section data. We do that by adding to the Relocation vector.
+
+      // .eh_frame is horribly special and can reference discarded sections. To
+      // avoid having to parse and recreate .eh_frame, we just replace any
+      // relocation in it pointing to discarded sections with R_*_NONE, which
+      // hopefully creates a frame that is ignored at runtime.
+      SectionBase *Section = cast<DefinedRegular>(Body).Section;
+      if (Section == &InputSection::Discarded) {
+        P->setSymbolAndType(0, 0, false);
+        continue;
+      }
+
+      if (Config->IsRela) {
+        P->r_addend += Body.getVA() - Section->getOutputSection()->Addr;
+      } else if (Config->Relocatable) {
+        const uint8_t *BufLoc = RelocatedSection->Data.begin() + Rel.r_offset;
+        RelocatedSection->Relocations.push_back(
+            {R_ABS, Type, Rel.r_offset, Target->getImplicitAddend(BufLoc, Type),
+             &Body});
+      }
+    }
+
+  }
+}
+
+// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak
+// references specially. The general rule is that the value of the symbol in
+// this context is the address of the place P. A further special case is that
+// branch relocations to an undefined weak reference resolve to the next
+// instruction.
+static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
+                                              uint32_t P) {
+  switch (Type) {
+  // Unresolved branch relocations to weak references resolve to next
+  // instruction, this will be either 2 or 4 bytes on from P.
+  case R_ARM_THM_JUMP11:
+    return P + 2 + A;
+  case R_ARM_CALL:
+  case R_ARM_JUMP24:
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+  case R_ARM_PREL31:
+  case R_ARM_THM_JUMP19:
+  case R_ARM_THM_JUMP24:
+    return P + 4 + A;
+  case R_ARM_THM_CALL:
+    // We don't want an interworking BLX to ARM
+    return P + 5 + A;
+  // Unresolved non branch pc-relative relocations
+  // R_ARM_TARGET2 which can be resolved relatively is not present as it never
+  // targets a weak-reference.
+  case R_ARM_MOVW_PREL_NC:
+  case R_ARM_MOVT_PREL:
+  case R_ARM_REL32:
+  case R_ARM_THM_MOVW_PREL_NC:
+  case R_ARM_THM_MOVT_PREL:
+    return P + A;
+  }
+  llvm_unreachable("ARM pc-relative relocation expected\n");
+}
+
+// The comment above getARMUndefinedRelativeWeakVA applies to this function.
+static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
+                                                  uint64_t P) {
+  switch (Type) {
+  // Unresolved branch relocations to weak references resolve to next
+  // instruction, this is 4 bytes on from P.
+  case R_AARCH64_CALL26:
+  case R_AARCH64_CONDBR19:
+  case R_AARCH64_JUMP26:
+  case R_AARCH64_TSTBR14:
+    return P + 4 + A;
+  // Unresolved non branch pc-relative relocations
+  case R_AARCH64_PREL16:
+  case R_AARCH64_PREL32:
+  case R_AARCH64_PREL64:
+  case R_AARCH64_ADR_PREL_LO21:
+    return P + A;
+  }
+  llvm_unreachable("AArch64 pc-relative relocation expected\n");
+}
+
+// ARM SBREL relocations are of the form S + A - B where B is the static base
+// The ARM ABI defines base to be "addressing origin of the output segment
+// defining the symbol S". We defined the "addressing origin"/static base to be
+// the base of the PT_LOAD segment containing the Body.
+// The procedure call standard only defines a Read Write Position Independent
+// RWPI variant so in practice we should expect the static base to be the base
+// of the RW segment.
+static uint64_t getARMStaticBase(const SymbolBody &Body) {
+  OutputSection *OS = Body.getOutputSection();
+  if (!OS || !OS->FirstInPtLoad)
+    fatal("SBREL relocation to " + Body.getName() + " without static base");
+  return OS->FirstInPtLoad->Addr;
+}
+
+static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P,
+                                 const SymbolBody &Body, RelExpr Expr) {
+  switch (Expr) {
+  case R_ABS:
+  case R_RELAX_GOT_PC_NOPIC:
+    return Body.getVA(A);
+  case R_ARM_SBREL:
+    return Body.getVA(A) - getARMStaticBase(Body);
+  case R_GOT:
+  case R_RELAX_TLS_GD_TO_IE_ABS:
+    return Body.getGotVA() + A;
+  case R_GOTONLY_PC:
+    return InX::Got->getVA() + A - P;
+  case R_GOTONLY_PC_FROM_END:
+    return InX::Got->getVA() + A - P + InX::Got->getSize();
+  case R_GOTREL:
+    return Body.getVA(A) - InX::Got->getVA();
+  case R_GOTREL_FROM_END:
+    return Body.getVA(A) - InX::Got->getVA() - InX::Got->getSize();
+  case R_GOT_FROM_END:
+  case R_RELAX_TLS_GD_TO_IE_END:
+    return Body.getGotOffset() + A - InX::Got->getSize();
+  case R_GOT_OFF:
+    return Body.getGotOffset() + A;
+  case R_GOT_PAGE_PC:
+  case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+    return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P);
+  case R_GOT_PC:
+  case R_RELAX_TLS_GD_TO_IE:
+    return Body.getGotVA() + A - P;
+  case R_HINT:
+  case R_NONE:
+  case R_TLSDESC_CALL:
+    llvm_unreachable("cannot relocate hint relocs");
+  case R_MIPS_GOTREL:
+    return Body.getVA(A) - InX::MipsGot->getGp();
+  case R_MIPS_GOT_GP:
+    return InX::MipsGot->getGp() + A;
+  case R_MIPS_GOT_GP_PC: {
+    // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
+    // is _gp_disp symbol. In that case we should use the following
+    // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
+    // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+    uint64_t V = InX::MipsGot->getGp() + A - P;
+    if (Type == R_MIPS_LO16)
+      V += 4;
+    return V;
+  }
+  case R_MIPS_GOT_LOCAL_PAGE:
+    // If relocation against MIPS local symbol requires GOT entry, this entry
+    // should be initialized by 'page address'. This address is high 16-bits
+    // of sum the symbol's value and the addend.
+    return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Body, A) -
+           InX::MipsGot->getGp();
+  case R_MIPS_GOT_OFF:
+  case R_MIPS_GOT_OFF32:
+    // In case of MIPS if a GOT relocation has non-zero addend this addend
+    // should be applied to the GOT entry content not to the GOT entry offset.
+    // That is why we use separate expression type.
+    return InX::MipsGot->getVA() + InX::MipsGot->getBodyEntryOffset(Body, A) -
+           InX::MipsGot->getGp();
+  case R_MIPS_TLSGD:
+    return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
+           InX::MipsGot->getGlobalDynOffset(Body) - InX::MipsGot->getGp();
+  case R_MIPS_TLSLD:
+    return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
+           InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp();
+  case R_PAGE_PC:
+  case R_PLT_PAGE_PC: {
+    uint64_t Dest;
+    if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+      Dest = getAArch64Page(A);
+    else
+      Dest = getAArch64Page(Body.getVA(A));
+    return Dest - getAArch64Page(P);
+  }
+  case R_PC: {
+    uint64_t Dest;
+    if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) {
+      // On ARM and AArch64 a branch to an undefined weak resolves to the
+      // next instruction, otherwise the place.
+      if (Config->EMachine == EM_ARM)
+        Dest = getARMUndefinedRelativeWeakVA(Type, A, P);
+      else if (Config->EMachine == EM_AARCH64)
+        Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P);
+      else
+        Dest = Body.getVA(A);
+    } else {
+      Dest = Body.getVA(A);
+    }
+    return Dest - P;
+  }
+  case R_PLT:
+    return Body.getPltVA() + A;
+  case R_PLT_PC:
+  case R_PPC_PLT_OPD:
+    return Body.getPltVA() + A - P;
+  case R_PPC_OPD: {
+    uint64_t SymVA = Body.getVA(A);
+    // If we have an undefined weak symbol, we might get here with a symbol
+    // address of zero. That could overflow, but the code must be unreachable,
+    // so don't bother doing anything at all.
+    if (!SymVA)
+      return 0;
+    if (Out::Opd) {
+      // If this is a local call, and we currently have the address of a
+      // function-descriptor, get the underlying code address instead.
+      uint64_t OpdStart = Out::Opd->Addr;
+      uint64_t OpdEnd = OpdStart + Out::Opd->Size;
+      bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
+      if (InOpd)
+        SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
+    }
+    return SymVA - P;
+  }
+  case R_PPC_TOC:
+    return getPPC64TocBase() + A;
+  case R_RELAX_GOT_PC:
+    return Body.getVA(A) - P;
+  case R_RELAX_TLS_GD_TO_LE:
+  case R_RELAX_TLS_IE_TO_LE:
+  case R_RELAX_TLS_LD_TO_LE:
+  case R_TLS:
+    // A weak undefined TLS symbol resolves to the base of the TLS
+    // block, i.e. gets a value of zero. If we pass --gc-sections to
+    // lld and .tbss is not referenced, it gets reclaimed and we don't
+    // create a TLS program header. Therefore, we resolve this
+    // statically to zero.
+    if (Body.isTls() && (Body.isLazy() || Body.isUndefined()) &&
+        Body.symbol()->isWeak())
+      return 0;
+    if (Target->TcbSize)
+      return Body.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
+    return Body.getVA(A) - Out::TlsPhdr->p_memsz;
+  case R_RELAX_TLS_GD_TO_LE_NEG:
+  case R_NEG_TLS:
+    return Out::TlsPhdr->p_memsz - Body.getVA(A);
+  case R_SIZE:
+    return A; // Body.getSize was already folded into the addend.
+  case R_TLSDESC:
+    return InX::Got->getGlobalDynAddr(Body) + A;
+  case R_TLSDESC_PAGE:
+    return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A) -
+           getAArch64Page(P);
+  case R_TLSGD:
+    return InX::Got->getGlobalDynOffset(Body) + A - InX::Got->getSize();
+  case R_TLSGD_PC:
+    return InX::Got->getGlobalDynAddr(Body) + A - P;
+  case R_TLSLD:
+    return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
+  case R_TLSLD_PC:
+    return InX::Got->getTlsIndexVA() + A - P;
+  }
+  llvm_unreachable("Invalid expression");
+}
+
+// This function applies relocations to sections without SHF_ALLOC bit.
+// Such sections are never mapped to memory at runtime. Debug sections are
+// an example. Relocations in non-alloc sections are much easier to
+// handle than in allocated sections because it will never need complex
+// treatement such as GOT or PLT (because at runtime no one refers them).
+// So, we handle relocations for non-alloc sections directly in this
+// function as a performance optimization.
+template <class ELFT, class RelTy>
+void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+  for (const RelTy &Rel : Rels) {
+    uint32_t Type = Rel.getType(Config->IsMips64EL);
+    uint64_t Offset = getOffset(Rel.r_offset);
+    uint8_t *BufLoc = Buf + Offset;
+    int64_t Addend = getAddend<ELFT>(Rel);
+    if (!RelTy::IsRela)
+      Addend += Target->getImplicitAddend(BufLoc, Type);
+
+    SymbolBody &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel);
+    RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
+    if (Expr == R_NONE)
+      continue;
+    if (Expr != R_ABS) {
+      error(this->getLocation<ELFT>(Offset) + ": has non-ABS reloc");
+      return;
+    }
+
+    uint64_t AddrLoc = getParent()->Addr + Offset;
+    uint64_t SymVA = 0;
+    if (!Sym.isTls() || Out::TlsPhdr)
+      SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
+          getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS));
+    Target->relocateOne(BufLoc, Type, SymVA);
+  }
+}
+
+template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const {
+  return cast_or_null<elf::ObjectFile<ELFT>>(File);
+}
+
+template <class ELFT>
+void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+  if (Flags & SHF_ALLOC)
+    relocateAlloc(Buf, BufEnd);
+  else
+    relocateNonAlloc<ELFT>(Buf, BufEnd);
+}
+
+template <class ELFT>
+void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) {
+  // scanReloc function in Writer.cpp constructs Relocations
+  // vector only for SHF_ALLOC'ed sections. For other sections,
+  // we handle relocations directly here.
+  auto *IS = cast<InputSection>(this);
+  assert(!(IS->Flags & SHF_ALLOC));
+  if (IS->AreRelocsRela)
+    IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>());
+  else
+    IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>());
+}
+
+void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
+  assert(Flags & SHF_ALLOC);
+  const unsigned Bits = Config->Wordsize * 8;
+  for (const Relocation &Rel : Relocations) {
+    uint64_t Offset = getOffset(Rel.Offset);
+    uint8_t *BufLoc = Buf + Offset;
+    uint32_t Type = Rel.Type;
+
+    uint64_t AddrLoc = getOutputSection()->Addr + Offset;
+    RelExpr Expr = Rel.Expr;
+    uint64_t TargetVA = SignExtend64(
+        getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
+
+    switch (Expr) {
+    case R_RELAX_GOT_PC:
+    case R_RELAX_GOT_PC_NOPIC:
+      Target->relaxGot(BufLoc, TargetVA);
+      break;
+    case R_RELAX_TLS_IE_TO_LE:
+      Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
+      break;
+    case R_RELAX_TLS_LD_TO_LE:
+      Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
+      break;
+    case R_RELAX_TLS_GD_TO_LE:
+    case R_RELAX_TLS_GD_TO_LE_NEG:
+      Target->relaxTlsGdToLe(BufLoc, Type, TargetVA);
+      break;
+    case R_RELAX_TLS_GD_TO_IE:
+    case R_RELAX_TLS_GD_TO_IE_ABS:
+    case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+    case R_RELAX_TLS_GD_TO_IE_END:
+      Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
+      break;
+    case R_PPC_PLT_OPD:
+      // Patch a nop (0x60000000) to a ld.
+      if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
+        write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
+      LLVM_FALLTHROUGH;
+    default:
+      Target->relocateOne(BufLoc, Type, TargetVA);
+      break;
+    }
+  }
+}
+
+template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
+  if (this->Type == SHT_NOBITS)
+    return;
+
+  if (auto *S = dyn_cast<SyntheticSection>(this)) {
+    S->writeTo(Buf + OutSecOff);
+    return;
+  }
+
+  // If -r or --emit-relocs is given, then an InputSection
+  // may be a relocation section.
+  if (this->Type == SHT_RELA) {
+    copyRelocations<ELFT>(Buf + OutSecOff,
+                          this->template getDataAs<typename ELFT::Rela>());
+    return;
+  }
+  if (this->Type == SHT_REL) {
+    copyRelocations<ELFT>(Buf + OutSecOff,
+                          this->template getDataAs<typename ELFT::Rel>());
+    return;
+  }
+
+  // If -r is given, we may have a SHT_GROUP section.
+  if (this->Type == SHT_GROUP) {
+    copyShtGroup<ELFT>(Buf + OutSecOff);
+    return;
+  }
+
+  // Copy section contents from source object file to output file
+  // and then apply relocations.
+  memcpy(Buf + OutSecOff, Data.data(), Data.size());
+  uint8_t *BufEnd = Buf + OutSecOff + Data.size();
+  this->relocate<ELFT>(Buf, BufEnd);
+}
+
+void InputSection::replace(InputSection *Other) {
+  this->Alignment = std::max(this->Alignment, Other->Alignment);
+  Other->Repl = this->Repl;
+  Other->Live = false;
+}
+
+template <class ELFT>
+EhInputSection::EhInputSection(elf::ObjectFile<ELFT> *F,
+                               const typename ELFT::Shdr *Header,
+                               StringRef Name)
+    : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {
+  // Mark .eh_frame sections as live by default because there are
+  // usually no relocations that point to .eh_frames. Otherwise,
+  // the garbage collector would drop all .eh_frame sections.
+  this->Live = true;
+}
+
+SyntheticSection *EhInputSection::getParent() const {
+  return cast_or_null<SyntheticSection>(Parent);
+}
+
+bool EhInputSection::classof(const SectionBase *S) {
+  return S->kind() == InputSectionBase::EHFrame;
+}
+
+// Returns the index of the first relocation that points to a region between
+// Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
+                         unsigned &RelocI) {
+  // Start search from RelocI for fast access. That works because the
+  // relocations are sorted in .eh_frame.
+  for (unsigned N = Rels.size(); RelocI < N; ++RelocI) {
+    const RelTy &Rel = Rels[RelocI];
+    if (Rel.r_offset < Begin)
+      continue;
+
+    if (Rel.r_offset < Begin + Size)
+      return RelocI;
+    return -1;
+  }
+  return -1;
+}
+
+// .eh_frame is a sequence of CIE or FDE records.
+// This function splits an input section into records and returns them.
+template <class ELFT> void EhInputSection::split() {
+  // Early exit if already split.
+  if (!this->Pieces.empty())
+    return;
+
+  if (this->NumRelocations) {
+    if (this->AreRelocsRela)
+      split<ELFT>(this->relas<ELFT>());
+    else
+      split<ELFT>(this->rels<ELFT>());
+    return;
+  }
+  split<ELFT>(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
+}
+
+template <class ELFT, class RelTy>
+void EhInputSection::split(ArrayRef<RelTy> Rels) {
+  ArrayRef<uint8_t> Data = this->Data;
+  unsigned RelI = 0;
+  for (size_t Off = 0, End = Data.size(); Off != End;) {
+    size_t Size = readEhRecordSize<ELFT>(this, Off);
+    this->Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI));
+    // The empty record is the end marker.
+    if (Size == 4)
+      break;
+    Off += Size;
+  }
+}
+
+static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
+  // Optimize the common case.
+  StringRef S((const char *)A.data(), A.size());
+  if (EntSize == 1)
+    return S.find(0);
+
+  for (unsigned I = 0, N = S.size(); I != N; I += EntSize) {
+    const char *B = S.begin() + I;
+    if (std::all_of(B, B + EntSize, [](char C) { return C == 0; }))
+      return I;
+  }
+  return StringRef::npos;
+}
+
+SyntheticSection *MergeInputSection::getParent() const {
+  return cast_or_null<SyntheticSection>(Parent);
+}
+
+// Split SHF_STRINGS section. Such section is a sequence of
+// null-terminated strings.
+void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) {
+  size_t Off = 0;
+  bool IsAlloc = this->Flags & SHF_ALLOC;
+  while (!Data.empty()) {
+    size_t End = findNull(Data, EntSize);
+    if (End == StringRef::npos)
+      fatal(toString(this) + ": string is not null terminated");
+    size_t Size = End + EntSize;
+    Pieces.emplace_back(Off, !IsAlloc);
+    Hashes.push_back(hash_value(toStringRef(Data.slice(0, Size))));
+    Data = Data.slice(Size);
+    Off += Size;
+  }
+}
+
+// Split non-SHF_STRINGS section. Such section is a sequence of
+// fixed size records.
+void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data,
+                                        size_t EntSize) {
+  size_t Size = Data.size();
+  assert((Size % EntSize) == 0);
+  bool IsAlloc = this->Flags & SHF_ALLOC;
+  for (unsigned I = 0, N = Size; I != N; I += EntSize) {
+    Hashes.push_back(hash_value(toStringRef(Data.slice(I, EntSize))));
+    Pieces.emplace_back(I, !IsAlloc);
+  }
+}
+
+template <class ELFT>
+MergeInputSection::MergeInputSection(elf::ObjectFile<ELFT> *F,
+                                     const typename ELFT::Shdr *Header,
+                                     StringRef Name)
+    : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {}
+
+// This function is called after we obtain a complete list of input sections
+// that need to be linked. This is responsible to split section contents
+// into small chunks for further processing.
+//
+// Note that this function is called from parallel_for_each. This must be
+// thread-safe (i.e. no memory allocation from the pools).
+void MergeInputSection::splitIntoPieces() {
+  ArrayRef<uint8_t> Data = this->Data;
+  uint64_t EntSize = this->Entsize;
+  if (this->Flags & SHF_STRINGS)
+    splitStrings(Data, EntSize);
+  else
+    splitNonStrings(Data, EntSize);
+
+  if (Config->GcSections && (this->Flags & SHF_ALLOC))
+    for (uint64_t Off : LiveOffsets)
+      this->getSectionPiece(Off)->Live = true;
+}
+
+bool MergeInputSection::classof(const SectionBase *S) {
+  return S->kind() == InputSectionBase::Merge;
+}
+
+// Do binary search to get a section piece at a given input offset.
+SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
+  auto *This = static_cast<const MergeInputSection *>(this);
+  return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
+}
+
+template <class It, class T, class Compare>
+static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
+  size_t Size = std::distance(First, Last);
+  assert(Size != 0);
+  while (Size != 1) {
+    size_t H = Size / 2;
+    const It MI = First + H;
+    Size -= H;
+    First = Comp(Value, *MI) ? First : First + H;
+  }
+  return Comp(Value, *First) ? First : First + 1;
+}
+
+const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const {
+  uint64_t Size = this->Data.size();
+  if (Offset >= Size)
+    fatal(toString(this) + ": entry is past the end of the section");
+
+  // Find the element this offset points to.
+  auto I = fastUpperBound(
+      Pieces.begin(), Pieces.end(), Offset,
+      [](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
+  --I;
+  return &*I;
+}
+
+// Returns the offset in an output section for a given input offset.
+// Because contents of a mergeable section is not contiguous in output,
+// it is not just an addition to a base output offset.
+uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
+  // Initialize OffsetMap lazily.
+  llvm::call_once(InitOffsetMap, [&] {
+    OffsetMap.reserve(Pieces.size());
+    for (const SectionPiece &Piece : Pieces)
+      OffsetMap[Piece.InputOff] = Piece.OutputOff;
+  });
+
+  // Find a string starting at a given offset.
+  auto It = OffsetMap.find(Offset);
+  if (It != OffsetMap.end())
+    return It->second;
+
+  if (!this->Live)
+    return 0;
+
+  // If Offset is not at beginning of a section piece, it is not in the map.
+  // In that case we need to search from the original section piece vector.
+  const SectionPiece &Piece = *this->getSectionPiece(Offset);
+  if (!Piece.Live)
+    return 0;
+
+  uint64_t Addend = Offset - Piece.InputOff;
+  return Piece.OutputOff + Addend;
+}
+
+template InputSection::InputSection(elf::ObjectFile<ELF32LE> *,
+                                    const ELF32LE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF32BE> *,
+                                    const ELF32BE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF64LE> *,
+                                    const ELF64LE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF64BE> *,
+                                    const ELF64BE::Shdr *, StringRef);
+
+template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t);
+
+template std::string InputSectionBase::getSrcMsg<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF64BE>(uint64_t);
+
+template std::string InputSectionBase::getObjMsg<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF64BE>(uint64_t);
+
+template void InputSection::writeTo<ELF32LE>(uint8_t *);
+template void InputSection::writeTo<ELF32BE>(uint8_t *);
+template void InputSection::writeTo<ELF64LE>(uint8_t *);
+template void InputSection::writeTo<ELF64BE>(uint8_t *);
+
+template elf::ObjectFile<ELF32LE> *InputSectionBase::getFile<ELF32LE>() const;
+template elf::ObjectFile<ELF32BE> *InputSectionBase::getFile<ELF32BE>() const;
+template elf::ObjectFile<ELF64LE> *InputSectionBase::getFile<ELF64LE>() const;
+template elf::ObjectFile<ELF64BE> *InputSectionBase::getFile<ELF64BE>() const;
+
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32LE> *,
+                                              const ELF32LE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32BE> *,
+                                              const ELF32BE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64LE> *,
+                                              const ELF64LE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64BE> *,
+                                              const ELF64BE::Shdr *, StringRef);
+
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF32LE> *,
+                                        const ELF32LE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF32BE> *,
+                                        const ELF32BE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF64LE> *,
+                                        const ELF64LE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF64BE> *,
+                                        const ELF64BE::Shdr *, StringRef);
+
+template void EhInputSection::split<ELF32LE>();
+template void EhInputSection::split<ELF32BE>();
+template void EhInputSection::split<ELF64LE>();
+template void EhInputSection::split<ELF64BE>();
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
new file mode 100644 (file)
index 0000000..d262b58
--- /dev/null
@@ -0,0 +1,339 @@
+//===- InputSection.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_INPUT_SECTION_H
+#define LLD_ELF_INPUT_SECTION_H
+
+#include "Config.h"
+#include "Relocations.h"
+#include "Thunks.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Threading.h"
+#include <mutex>
+
+namespace lld {
+namespace elf {
+
+class DefinedCommon;
+class SymbolBody;
+struct SectionPiece;
+
+class DefinedRegular;
+class SyntheticSection;
+template <class ELFT> class EhFrameSection;
+class MergeSyntheticSection;
+template <class ELFT> class ObjectFile;
+class OutputSection;
+
+// This is the base class of all sections that lld handles. Some are sections in
+// input files, some are sections in the produced output file and some exist
+// just as a convenience for implementing special ways of combining some
+// sections.
+class SectionBase {
+public:
+  enum Kind { Regular, EHFrame, Merge, Synthetic, Output };
+
+  Kind kind() const { return (Kind)SectionKind; }
+
+  StringRef Name;
+
+  unsigned SectionKind : 3;
+
+  // The next two bit fields are only used by InputSectionBase, but we
+  // put them here so the struct packs better.
+
+  // The garbage collector sets sections' Live bits.
+  // If GC is disabled, all sections are considered live by default.
+  unsigned Live : 1;     // for garbage collection
+  unsigned Assigned : 1; // for linker script
+
+  uint32_t Alignment;
+
+  // These corresponds to the fields in Elf_Shdr.
+  uint64_t Flags;
+  uint64_t Entsize;
+  uint32_t Type;
+  uint32_t Link;
+  uint32_t Info;
+
+  OutputSection *getOutputSection();
+  const OutputSection *getOutputSection() const {
+    return const_cast<SectionBase *>(this)->getOutputSection();
+  }
+
+  // Translate an offset in the input section to an offset in the output
+  // section.
+  uint64_t getOffset(uint64_t Offset) const;
+
+  uint64_t getOffset(const DefinedRegular &Sym) const;
+
+protected:
+  SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
+              uint64_t Entsize, uint64_t Alignment, uint32_t Type,
+              uint32_t Info, uint32_t Link)
+      : Name(Name), SectionKind(SectionKind), Alignment(Alignment),
+        Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) {
+    Live = false;
+    Assigned = false;
+  }
+};
+
+// This corresponds to a section of an input file.
+class InputSectionBase : public SectionBase {
+public:
+  static bool classof(const SectionBase *S);
+
+  // The file this section is from.
+  InputFile *File;
+
+  ArrayRef<uint8_t> Data;
+  uint64_t getOffsetInFile() const;
+
+  static InputSectionBase Discarded;
+
+  InputSectionBase()
+      : SectionBase(Regular, "", /*Flags*/ 0, /*Entsize*/ 0, /*Alignment*/ 0,
+                    /*Type*/ 0,
+                    /*Info*/ 0, /*Link*/ 0),
+        Repl(this) {
+    Live = false;
+    Assigned = false;
+    NumRelocations = 0;
+    AreRelocsRela = false;
+  }
+
+  template <class ELFT>
+  InputSectionBase(ObjectFile<ELFT> *File, const typename ELFT::Shdr *Header,
+                   StringRef Name, Kind SectionKind);
+
+  InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type,
+                   uint64_t Entsize, uint32_t Link, uint32_t Info,
+                   uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name,
+                   Kind SectionKind);
+
+  // Input sections are part of an output section. Special sections
+  // like .eh_frame and merge sections are first combined into a
+  // synthetic section that is then added to an output section. In all
+  // cases this points one level up.
+  SectionBase *Parent = nullptr;
+
+  // Relocations that refer to this section.
+  const void *FirstRelocation = nullptr;
+  unsigned NumRelocations : 31;
+  unsigned AreRelocsRela : 1;
+  template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const {
+    assert(!AreRelocsRela);
+    return llvm::makeArrayRef(
+        static_cast<const typename ELFT::Rel *>(FirstRelocation),
+        NumRelocations);
+  }
+  template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const {
+    assert(AreRelocsRela);
+    return llvm::makeArrayRef(
+        static_cast<const typename ELFT::Rela *>(FirstRelocation),
+        NumRelocations);
+  }
+
+  // This pointer points to the "real" instance of this instance.
+  // Usually Repl == this. However, if ICF merges two sections,
+  // Repl pointer of one section points to another section. So,
+  // if you need to get a pointer to this instance, do not use
+  // this but instead this->Repl.
+  InputSectionBase *Repl;
+
+  // InputSections that are dependent on us (reverse dependency for GC)
+  llvm::TinyPtrVector<InputSectionBase *> DependentSections;
+
+  // Returns the size of this section (even if this is a common or BSS.)
+  size_t getSize() const;
+
+  template <class ELFT> ObjectFile<ELFT> *getFile() const;
+
+  template <class ELFT> llvm::object::ELFFile<ELFT> getObj() const {
+    return getFile<ELFT>()->getObj();
+  }
+
+  InputSection *getLinkOrderDep() const;
+
+  void uncompress();
+
+  // Returns a source location string. Used to construct an error message.
+  template <class ELFT> std::string getLocation(uint64_t Offset);
+  template <class ELFT> std::string getSrcMsg(uint64_t Offset);
+  template <class ELFT> std::string getObjMsg(uint64_t Offset);
+
+  template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);
+  void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd);
+  template <class ELFT> void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd);
+
+  std::vector<Relocation> Relocations;
+
+  template <typename T> llvm::ArrayRef<T> getDataAs() const {
+    size_t S = Data.size();
+    assert(S % sizeof(T) == 0);
+    return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+  }
+};
+
+// SectionPiece represents a piece of splittable section contents.
+// We allocate a lot of these and binary search on them. This means that they
+// have to be as compact as possible, which is why we don't store the size (can
+// be found by looking at the next one) and put the hash in a side table.
+struct SectionPiece {
+  SectionPiece(size_t Off, bool Live = false)
+      : InputOff(Off), OutputOff(-1), Live(Live || !Config->GcSections) {}
+
+  size_t InputOff;
+  ssize_t OutputOff : 8 * sizeof(ssize_t) - 1;
+  size_t Live : 1;
+};
+static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t),
+              "SectionPiece is too big");
+
+// This corresponds to a SHF_MERGE section of an input file.
+class MergeInputSection : public InputSectionBase {
+public:
+  template <class ELFT>
+  MergeInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
+                    StringRef Name);
+  static bool classof(const SectionBase *S);
+  void splitIntoPieces();
+
+  // Mark the piece at a given offset live. Used by GC.
+  void markLiveAt(uint64_t Offset) {
+    assert(this->Flags & llvm::ELF::SHF_ALLOC);
+    LiveOffsets.insert(Offset);
+  }
+
+  // Translate an offset in the input section to an offset
+  // in the output section.
+  uint64_t getOffset(uint64_t Offset) const;
+
+  // Splittable sections are handled as a sequence of data
+  // rather than a single large blob of data.
+  std::vector<SectionPiece> Pieces;
+
+  // Returns I'th piece's data. This function is very hot when
+  // string merging is enabled, so we want to inline.
+  LLVM_ATTRIBUTE_ALWAYS_INLINE
+  llvm::CachedHashStringRef getData(size_t I) const {
+    size_t Begin = Pieces[I].InputOff;
+    size_t End;
+    if (Pieces.size() - 1 == I)
+      End = this->Data.size();
+    else
+      End = Pieces[I + 1].InputOff;
+
+    StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin};
+    return {S, Hashes[I]};
+  }
+
+  // Returns the SectionPiece at a given input section offset.
+  SectionPiece *getSectionPiece(uint64_t Offset);
+  const SectionPiece *getSectionPiece(uint64_t Offset) const;
+
+  SyntheticSection *getParent() const;
+
+private:
+  void splitStrings(ArrayRef<uint8_t> A, size_t Size);
+  void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
+
+  std::vector<uint32_t> Hashes;
+
+  mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap;
+  mutable llvm::once_flag InitOffsetMap;
+
+  llvm::DenseSet<uint64_t> LiveOffsets;
+};
+
+struct EhSectionPiece : public SectionPiece {
+  EhSectionPiece(size_t Off, InputSectionBase *ID, uint32_t Size,
+                 unsigned FirstRelocation)
+      : SectionPiece(Off, false), ID(ID), Size(Size),
+        FirstRelocation(FirstRelocation) {}
+  InputSectionBase *ID;
+  uint32_t Size;
+  uint32_t size() const { return Size; }
+
+  ArrayRef<uint8_t> data() { return {ID->Data.data() + this->InputOff, Size}; }
+  unsigned FirstRelocation;
+};
+
+// This corresponds to a .eh_frame section of an input file.
+class EhInputSection : public InputSectionBase {
+public:
+  template <class ELFT>
+  EhInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
+                 StringRef Name);
+  static bool classof(const SectionBase *S);
+  template <class ELFT> void split();
+  template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels);
+
+  // Splittable sections are handled as a sequence of data
+  // rather than a single large blob of data.
+  std::vector<EhSectionPiece> Pieces;
+
+  SyntheticSection *getParent() const;
+};
+
+// This is a section that is added directly to an output section
+// instead of needing special combination via a synthetic section. This
+// includes all input sections with the exceptions of SHF_MERGE and
+// .eh_frame. It also includes the synthetic sections themselves.
+class InputSection : public InputSectionBase {
+public:
+  InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+               ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular);
+  template <class ELFT>
+  InputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
+               StringRef Name);
+
+  // Write this section to a mmap'ed file, assuming Buf is pointing to
+  // beginning of the output section.
+  template <class ELFT> void writeTo(uint8_t *Buf);
+
+  OutputSection *getParent() const;
+
+  // The offset from beginning of the output sections this section was assigned
+  // to. The writer sets a value.
+  uint64_t OutSecOff = 0;
+
+  static bool classof(const SectionBase *S);
+
+  InputSectionBase *getRelocatedSection();
+
+  template <class ELFT, class RelTy>
+  void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+  // Used by ICF.
+  uint32_t Class[2] = {0, 0};
+
+  // Called by ICF to merge two input sections.
+  void replace(InputSection *Other);
+
+private:
+  template <class ELFT, class RelTy>
+  void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+  template <class ELFT> void copyShtGroup(uint8_t *Buf);
+};
+
+// The list of all input sections.
+extern std::vector<InputSectionBase *> InputSections;
+
+} // namespace elf
+
+std::string toString(const elf::InputSectionBase *);
+} // namespace lld
+
+#endif
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
new file mode 100644 (file)
index 0000000..3a53627
--- /dev/null
@@ -0,0 +1,191 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Core/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// This is for use when debugging LTO.
+static void saveBuffer(StringRef Buffer, const Twine &Path) {
+  std::error_code EC;
+  raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+  if (EC)
+    error("cannot create " + Path + ": " + EC.message());
+  OS << Buffer;
+}
+
+static void diagnosticHandler(const DiagnosticInfo &DI) {
+  SmallString<128> ErrStorage;
+  raw_svector_ostream OS(ErrStorage);
+  DiagnosticPrinterRawOStream DP(OS);
+  DI.print(DP);
+  warn(ErrStorage);
+}
+
+static void checkError(Error E) {
+  handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
+    error(EIB.message());
+    return Error::success();
+  });
+}
+
+static std::unique_ptr<lto::LTO> createLTO() {
+  lto::Config Conf;
+
+  // LLD supports the new relocations.
+  Conf.Options = InitTargetOptionsFromCodeGenFlags();
+  Conf.Options.RelaxELFRelocations = true;
+
+  if (Config->Relocatable)
+    Conf.RelocModel = None;
+  else if (Config->Pic)
+    Conf.RelocModel = Reloc::PIC_;
+  else
+    Conf.RelocModel = Reloc::Static;
+  Conf.CodeModel = GetCodeModelFromCMModel();
+  Conf.DisableVerify = Config->DisableVerify;
+  Conf.DiagHandler = diagnosticHandler;
+  Conf.OptLevel = Config->LTOO;
+
+  // Set up a custom pipeline if we've been asked to.
+  Conf.OptPipeline = Config->LTONewPmPasses;
+  Conf.AAPipeline = Config->LTOAAPipeline;
+
+  // Set up optimization remarks if we've been asked to.
+  Conf.RemarksFilename = Config->OptRemarksFilename;
+  Conf.RemarksWithHotness = Config->OptRemarksWithHotness;
+
+  if (Config->SaveTemps)
+    checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
+                                 /*UseInputModulePath*/ true));
+
+  lto::ThinBackend Backend;
+  if (Config->ThinLTOJobs != -1u)
+    Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+  return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+                                     Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+  replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
+                         STV_DEFAULT, S->body()->Type, nullptr);
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+  lto::InputFile &Obj = *F.Obj;
+  unsigned SymNum = 0;
+  std::vector<Symbol *> Syms = F.getSymbols();
+  std::vector<lto::SymbolResolution> Resols(Syms.size());
+
+  // Provide a resolution to the LTO API for each symbol.
+  for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+    Symbol *Sym = Syms[SymNum];
+    lto::SymbolResolution &R = Resols[SymNum];
+    ++SymNum;
+    SymbolBody *B = Sym->body();
+
+    // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+    // reports two symbols for module ASM defined. Without this check, lld
+    // flags an undefined in IR with a definition in ASM as prevailing.
+    // Once IRObjectFile is fixed to report only one symbol this hack can
+    // be removed.
+    R.Prevailing = !ObjSym.isUndefined() && B->File == &F;
+
+    R.VisibleToRegularObj =
+        Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
+    if (R.Prevailing)
+      undefine(Sym);
+    R.LinkerRedefined = Config->RenamedSymbols.count(Sym);
+  }
+  checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting ObjectFile(s).
+std::vector<InputFile *> BitcodeCompiler::compile() {
+  std::vector<InputFile *> Ret;
+  unsigned MaxTasks = LTOObj->getMaxTasks();
+  Buff.resize(MaxTasks);
+  Files.resize(MaxTasks);
+
+  // The --thinlto-cache-dir option specifies the path to a directory in which
+  // to cache native object files for ThinLTO incremental builds. If a path was
+  // specified, configure LTO to use it as the cache directory.
+  lto::NativeObjectCache Cache;
+  if (!Config->ThinLTOCacheDir.empty())
+    Cache = check(
+        lto::localCache(Config->ThinLTOCacheDir,
+                        [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+                          Files[Task] = std::move(MB);
+                        }));
+
+  checkError(LTOObj->run(
+      [&](size_t Task) {
+        return llvm::make_unique<lto::NativeObjectStream>(
+            llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+      },
+      Cache));
+
+  if (!Config->ThinLTOCacheDir.empty())
+    pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+
+  for (unsigned I = 0; I != MaxTasks; ++I) {
+    if (Buff[I].empty())
+      continue;
+    if (Config->SaveTemps) {
+      if (I == 0)
+        saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
+      else
+        saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
+    }
+    InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
+    Ret.push_back(Obj);
+  }
+
+  for (std::unique_ptr<MemoryBuffer> &File : Files)
+    if (File)
+      Ret.push_back(createObjectFile(*File));
+
+  return Ret;
+}
diff --git a/ELF/LTO.h b/ELF/LTO.h
new file mode 100644 (file)
index 0000000..d19923c
--- /dev/null
+++ b/ELF/LTO.h
@@ -0,0 +1,57 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one ELF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular ELF files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// an ELF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_LTO_H
+#define LLD_ELF_LTO_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+} // namespace llvm
+
+namespace lld {
+namespace elf {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+  BitcodeCompiler();
+  ~BitcodeCompiler();
+
+  void add(BitcodeFile &F);
+  std::vector<InputFile *> compile();
+
+private:
+  std::unique_ptr<llvm::lto::LTO> LTOObj;
+  std::vector<SmallString<0>> Buff;
+  std::vector<std::unique_ptr<MemoryBuffer>> Files;
+};
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
new file mode 100644 (file)
index 0000000..8bdbd8d
--- /dev/null
@@ -0,0 +1,1255 @@
+//===- LinkerScript.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the parser/evaluator of the linker script.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinkerScript.h"
+#include "Config.h"
+#include "InputSection.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Threads.h"
+#include "Writer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::elf;
+
+LinkerScript *elf::Script;
+
+uint64_t ExprValue::getValue() const {
+  if (Sec) {
+    if (OutputSection *OS = Sec->getOutputSection())
+      return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment);
+    error(Loc + ": unable to evaluate expression: input section " + Sec->Name +
+          " has no output section assigned");
+  }
+  return alignTo(Val, Alignment);
+}
+
+uint64_t ExprValue::getSecAddr() const {
+  if (Sec)
+    return Sec->getOffset(0) + Sec->getOutputSection()->Addr;
+  return 0;
+}
+
+template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) {
+  Symbol *Sym;
+  uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+  std::tie(Sym, std::ignore) = Symtab<ELFT>::X->insert(
+      Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false,
+      /*File*/ nullptr);
+  Sym->Binding = STB_GLOBAL;
+  ExprValue Value = Cmd->Expression();
+  SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec;
+
+  // We want to set symbol values early if we can. This allows us to use symbols
+  // as variables in linker scripts. Doing so allows us to write expressions
+  // like this: `alignment = 16; . = ALIGN(., alignment)`
+  uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0;
+  replaceBody<DefinedRegular>(Sym, Cmd->Name, /*IsLocal=*/false, Visibility,
+                              STT_NOTYPE, SymValue, 0, Sec, nullptr);
+  return Sym->body();
+}
+
+OutputSectionCommand *
+LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) {
+  OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
+  OutputSectionCommand *Cmd;
+  if (CmdRef && CmdRef->Location.empty()) {
+    // There was a forward reference.
+    Cmd = CmdRef;
+  } else {
+    Cmd = make<OutputSectionCommand>(Name);
+    if (!CmdRef)
+      CmdRef = Cmd;
+  }
+  Cmd->Location = Location;
+  return Cmd;
+}
+
+OutputSectionCommand *
+LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) {
+  OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
+  if (!CmdRef)
+    CmdRef = make<OutputSectionCommand>(Name);
+  return CmdRef;
+}
+
+void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
+  uint64_t Val = E().getValue();
+  if (Val < Dot && InSec)
+    error(Loc + ": unable to move location counter backward for: " +
+          CurAddressState->OutSec->Name);
+  Dot = Val;
+  // Update to location counter means update to section size.
+  if (InSec)
+    CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
+}
+
+// Sets value of a symbol. Two kinds of symbols are processed: synthetic
+// symbols, whose value is an offset from beginning of section and regular
+// symbols whose value is absolute.
+void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) {
+  if (Cmd->Name == ".") {
+    setDot(Cmd->Expression, Cmd->Location, InSec);
+    return;
+  }
+
+  if (!Cmd->Sym)
+    return;
+
+  auto *Sym = cast<DefinedRegular>(Cmd->Sym);
+  ExprValue V = Cmd->Expression();
+  if (V.isAbsolute()) {
+    Sym->Value = V.getValue();
+  } else {
+    Sym->Section = V.Sec;
+    Sym->Value = alignTo(V.Val, V.Alignment);
+  }
+}
+
+static SymbolBody *findSymbol(StringRef S) {
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    return Symtab<ELF32LE>::X->find(S);
+  case ELF32BEKind:
+    return Symtab<ELF32BE>::X->find(S);
+  case ELF64LEKind:
+    return Symtab<ELF64LE>::X->find(S);
+  case ELF64BEKind:
+    return Symtab<ELF64BE>::X->find(S);
+  default:
+    llvm_unreachable("unknown Config->EKind");
+  }
+}
+
+static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) {
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    return addRegular<ELF32LE>(Cmd);
+  case ELF32BEKind:
+    return addRegular<ELF32BE>(Cmd);
+  case ELF64LEKind:
+    return addRegular<ELF64LE>(Cmd);
+  case ELF64BEKind:
+    return addRegular<ELF64BE>(Cmd);
+  default:
+    llvm_unreachable("unknown Config->EKind");
+  }
+}
+
+void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+  if (Cmd->Name == ".")
+    return;
+
+  // If a symbol was in PROVIDE(), we need to define it only when
+  // it is a referenced undefined symbol.
+  SymbolBody *B = findSymbol(Cmd->Name);
+  if (Cmd->Provide && (!B || B->isDefined()))
+    return;
+
+  Cmd->Sym = addRegularSymbol(Cmd);
+}
+
+bool SymbolAssignment::classof(const BaseCommand *C) {
+  return C->Kind == AssignmentKind;
+}
+
+bool OutputSectionCommand::classof(const BaseCommand *C) {
+  return C->Kind == OutputSectionKind;
+}
+
+// Fill [Buf, Buf + Size) with Filler.
+// This is used for linker script "=fillexp" command.
+static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
+  size_t I = 0;
+  for (; I + 4 < Size; I += 4)
+    memcpy(Buf + I, &Filler, 4);
+  memcpy(Buf + I, &Filler, Size - I);
+}
+
+bool InputSectionDescription::classof(const BaseCommand *C) {
+  return C->Kind == InputSectionKind;
+}
+
+bool AssertCommand::classof(const BaseCommand *C) {
+  return C->Kind == AssertKind;
+}
+
+bool BytesDataCommand::classof(const BaseCommand *C) {
+  return C->Kind == BytesDataKind;
+}
+
+static StringRef basename(InputSectionBase *S) {
+  if (S->File)
+    return sys::path::filename(S->File->getName());
+  return "";
+}
+
+bool LinkerScript::shouldKeep(InputSectionBase *S) {
+  for (InputSectionDescription *ID : Opt.KeptSections)
+    if (ID->FilePat.match(basename(S)))
+      for (SectionPattern &P : ID->SectionPatterns)
+        if (P.SectionPat.match(S->Name))
+          return true;
+  return false;
+}
+
+// If an input string is in the form of "foo.N" where N is a number,
+// return N. Otherwise, returns 65536, which is one greater than the
+// lowest priority.
+static int getPriority(StringRef S) {
+  size_t Pos = S.rfind('.');
+  if (Pos == StringRef::npos)
+    return 65536;
+  int V;
+  if (!to_integer(S.substr(Pos + 1), V, 10))
+    return 65536;
+  return V;
+}
+
+// A helper function for the SORT() command.
+static std::function<bool(InputSectionBase *, InputSectionBase *)>
+getComparator(SortSectionPolicy K) {
+  switch (K) {
+  case SortSectionPolicy::Alignment:
+    return [](InputSectionBase *A, InputSectionBase *B) {
+      // ">" is not a mistake. Sections with larger alignments are placed
+      // before sections with smaller alignments in order to reduce the
+      // amount of padding necessary. This is compatible with GNU.
+      return A->Alignment > B->Alignment;
+    };
+  case SortSectionPolicy::Name:
+    return [](InputSectionBase *A, InputSectionBase *B) {
+      return A->Name < B->Name;
+    };
+  case SortSectionPolicy::Priority:
+    return [](InputSectionBase *A, InputSectionBase *B) {
+      return getPriority(A->Name) < getPriority(B->Name);
+    };
+  default:
+    llvm_unreachable("unknown sort policy");
+  }
+}
+
+// A helper function for the SORT() command.
+static bool matchConstraints(ArrayRef<InputSectionBase *> Sections,
+                             ConstraintKind Kind) {
+  if (Kind == ConstraintKind::NoConstraint)
+    return true;
+
+  bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) {
+    return static_cast<InputSectionBase *>(Sec)->Flags & SHF_WRITE;
+  });
+
+  return (IsRW && Kind == ConstraintKind::ReadWrite) ||
+         (!IsRW && Kind == ConstraintKind::ReadOnly);
+}
+
+static void sortSections(InputSection **Begin, InputSection **End,
+                         SortSectionPolicy K) {
+  if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
+    std::stable_sort(Begin, End, getComparator(K));
+}
+
+// Compute and remember which sections the InputSectionDescription matches.
+std::vector<InputSection *>
+LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
+  std::vector<InputSection *> Ret;
+
+  // Collects all sections that satisfy constraints of Cmd.
+  for (const SectionPattern &Pat : Cmd->SectionPatterns) {
+    size_t SizeBefore = Ret.size();
+
+    for (InputSectionBase *Sec : InputSections) {
+      if (Sec->Assigned)
+        continue;
+
+      if (!Sec->Live) {
+        reportDiscarded(Sec);
+        continue;
+      }
+
+      // For -emit-relocs we have to ignore entries like
+      //   .rela.dyn : { *(.rela.data) }
+      // which are common because they are in the default bfd script.
+      if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
+        continue;
+
+      StringRef Filename = basename(Sec);
+      if (!Cmd->FilePat.match(Filename) ||
+          Pat.ExcludedFilePat.match(Filename) ||
+          !Pat.SectionPat.match(Sec->Name))
+        continue;
+
+      Ret.push_back(cast<InputSection>(Sec));
+      Sec->Assigned = true;
+    }
+
+    // Sort sections as instructed by SORT-family commands and --sort-section
+    // option. Because SORT-family commands can be nested at most two depth
+    // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command
+    // line option is respected even if a SORT command is given, the exact
+    // behavior we have here is a bit complicated. Here are the rules.
+    //
+    // 1. If two SORT commands are given, --sort-section is ignored.
+    // 2. If one SORT command is given, and if it is not SORT_NONE,
+    //    --sort-section is handled as an inner SORT command.
+    // 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
+    // 4. If no SORT command is given, sort according to --sort-section.
+    InputSection **Begin = Ret.data() + SizeBefore;
+    InputSection **End = Ret.data() + Ret.size();
+    if (Pat.SortOuter != SortSectionPolicy::None) {
+      if (Pat.SortInner == SortSectionPolicy::Default)
+        sortSections(Begin, End, Config->SortSection);
+      else
+        sortSections(Begin, End, Pat.SortInner);
+      sortSections(Begin, End, Pat.SortOuter);
+    }
+  }
+  return Ret;
+}
+
+void LinkerScript::discard(ArrayRef<InputSectionBase *> V) {
+  for (InputSectionBase *S : V) {
+    S->Live = false;
+    if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
+        S == InX::DynStrTab)
+      error("discarding " + S->Name + " section is not allowed");
+    discard(S->DependentSections);
+  }
+}
+
+std::vector<InputSectionBase *>
+LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) {
+  std::vector<InputSectionBase *> Ret;
+
+  for (BaseCommand *Base : OutCmd.Commands) {
+    auto *Cmd = dyn_cast<InputSectionDescription>(Base);
+    if (!Cmd)
+      continue;
+
+    Cmd->Sections = computeInputSections(Cmd);
+    Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end());
+  }
+
+  return Ret;
+}
+
+void LinkerScript::processCommands(OutputSectionFactory &Factory) {
+  // A symbol can be assigned before any section is mentioned in the linker
+  // script. In an DSO, the symbol values are addresses, so the only important
+  // section values are:
+  // * SHN_UNDEF
+  // * SHN_ABS
+  // * Any value meaning a regular section.
+  // To handle that, create a dummy aether section that fills the void before
+  // the linker scripts switches to another section. It has an index of one
+  // which will map to whatever the first actual section is.
+  Aether = make<OutputSection>("", 0, SHF_ALLOC);
+  Aether->SectionIndex = 1;
+  auto State = make_unique<AddressState>(Opt);
+  // CurAddressState captures the local AddressState and makes it accessible
+  // deliberately. This is needed as there are some cases where we cannot just
+  // thread the current state through to a lambda function created by the
+  // script parser.
+  CurAddressState = State.get();
+  CurAddressState->OutSec = Aether;
+  Dot = 0;
+
+  for (size_t I = 0; I < Opt.Commands.size(); ++I) {
+    // Handle symbol assignments outside of any output section.
+    if (auto *Cmd = dyn_cast<SymbolAssignment>(Opt.Commands[I])) {
+      addSymbol(Cmd);
+      continue;
+    }
+
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I])) {
+      std::vector<InputSectionBase *> V = createInputSectionList(*Cmd);
+
+      // The output section name `/DISCARD/' is special.
+      // Any input section assigned to it is discarded.
+      if (Cmd->Name == "/DISCARD/") {
+        discard(V);
+        continue;
+      }
+
+      // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive
+      // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input
+      // sections satisfy a given constraint. If not, a directive is handled
+      // as if it wasn't present from the beginning.
+      //
+      // Because we'll iterate over Commands many more times, the easiest
+      // way to "make it as if it wasn't present" is to just remove it.
+      if (!matchConstraints(V, Cmd->Constraint)) {
+        for (InputSectionBase *S : V)
+          S->Assigned = false;
+        Opt.Commands.erase(Opt.Commands.begin() + I);
+        --I;
+        continue;
+      }
+
+      // A directive may contain symbol definitions like this:
+      // ".foo : { ...; bar = .; }". Handle them.
+      for (BaseCommand *Base : Cmd->Commands)
+        if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base))
+          addSymbol(OutCmd);
+
+      // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
+      // is given, input sections are aligned to that value, whether the
+      // given value is larger or smaller than the original section alignment.
+      if (Cmd->SubalignExpr) {
+        uint32_t Subalign = Cmd->SubalignExpr().getValue();
+        for (InputSectionBase *S : V)
+          S->Alignment = Subalign;
+      }
+
+      // Add input sections to an output section.
+      for (InputSectionBase *S : V)
+        Factory.addInputSec(S, Cmd->Name, Cmd->Sec);
+      if (OutputSection *Sec = Cmd->Sec) {
+        assert(Sec->SectionIndex == INT_MAX);
+        Sec->SectionIndex = I;
+        if (Cmd->Noload)
+          Sec->Type = SHT_NOBITS;
+        SecToCommand[Sec] = Cmd;
+      }
+    }
+  }
+  CurAddressState = nullptr;
+}
+
+void LinkerScript::fabricateDefaultCommands() {
+  std::vector<BaseCommand *> Commands;
+
+  // Define start address
+  uint64_t StartAddr = -1;
+
+  // The Sections with -T<section> have been sorted in order of ascending
+  // address. We must lower StartAddr if the lowest -T<section address> as
+  // calls to setDot() must be monotonically increasing.
+  for (auto &KV : Config->SectionStartMap)
+    StartAddr = std::min(StartAddr, KV.second);
+
+  Commands.push_back(make<SymbolAssignment>(
+      ".",
+      [=] {
+        return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize());
+      },
+      ""));
+
+  // For each OutputSection that needs a VA fabricate an OutputSectionCommand
+  // with an InputSectionDescription describing the InputSections
+  for (OutputSection *Sec : OutputSections) {
+    auto *OSCmd = createOutputSectionCommand(Sec->Name, "<internal>");
+    OSCmd->Sec = Sec;
+    SecToCommand[Sec] = OSCmd;
+
+    Commands.push_back(OSCmd);
+    if (Sec->Sections.size()) {
+      auto *ISD = make<InputSectionDescription>("");
+      OSCmd->Commands.push_back(ISD);
+      for (InputSection *ISec : Sec->Sections) {
+        ISD->Sections.push_back(ISec);
+        ISec->Assigned = true;
+      }
+    }
+  }
+  // SECTIONS commands run before other non SECTIONS commands
+  Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end());
+  Opt.Commands = std::move(Commands);
+}
+
+// Add sections that didn't match any sections command.
+void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
+  unsigned NumCommands = Opt.Commands.size();
+  for (InputSectionBase *S : InputSections) {
+    if (!S->Live || S->Parent)
+      continue;
+    StringRef Name = getOutputSectionName(S->Name);
+    auto End = Opt.Commands.begin() + NumCommands;
+    auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) {
+      if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+        return Cmd->Name == Name;
+      return false;
+    });
+    OutputSectionCommand *Cmd;
+    if (I == End) {
+      Factory.addInputSec(S, Name);
+      OutputSection *Sec = S->getOutputSection();
+      assert(Sec->SectionIndex == INT_MAX);
+      OutputSectionCommand *&CmdRef = SecToCommand[Sec];
+      if (!CmdRef) {
+        CmdRef = createOutputSectionCommand(Sec->Name, "<internal>");
+        CmdRef->Sec = Sec;
+        Opt.Commands.push_back(CmdRef);
+      }
+      Cmd = CmdRef;
+    } else {
+      Cmd = cast<OutputSectionCommand>(*I);
+      Factory.addInputSec(S, Name, Cmd->Sec);
+      if (OutputSection *Sec = Cmd->Sec) {
+        SecToCommand[Sec] = Cmd;
+        unsigned Index = std::distance(Opt.Commands.begin(), I);
+        assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index);
+        Sec->SectionIndex = Index;
+      }
+    }
+    auto *ISD = make<InputSectionDescription>("");
+    ISD->Sections.push_back(cast<InputSection>(S));
+    Cmd->Commands.push_back(ISD);
+  }
+}
+
+uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) {
+  bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) &&
+                CurAddressState->OutSec->Type == SHT_NOBITS;
+  uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot;
+  Start = alignTo(Start, Align);
+  uint64_t End = Start + Size;
+
+  if (IsTbss)
+    CurAddressState->ThreadBssOffset = End - Dot;
+  else
+    Dot = End;
+  return End;
+}
+
+void LinkerScript::output(InputSection *S) {
+  uint64_t Pos = advance(S->getSize(), S->Alignment);
+  S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr;
+
+  // Update output section size after adding each section. This is so that
+  // SIZEOF works correctly in the case below:
+  // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
+  CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr;
+
+  // If there is a memory region associated with this input section, then
+  // place the section in that region and update the region index.
+  if (CurAddressState->MemRegion) {
+    uint64_t &CurOffset =
+        CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
+    CurOffset += CurAddressState->OutSec->Size;
+    uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin;
+    if (CurSize > CurAddressState->MemRegion->Length) {
+      uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length;
+      error("section '" + CurAddressState->OutSec->Name +
+            "' will not fit in region '" + CurAddressState->MemRegion->Name +
+            "': overflowed by " + Twine(OverflowAmt) + " bytes");
+    }
+  }
+}
+
+void LinkerScript::switchTo(OutputSection *Sec) {
+  if (CurAddressState->OutSec == Sec)
+    return;
+
+  CurAddressState->OutSec = Sec;
+  CurAddressState->OutSec->Addr =
+      advance(0, CurAddressState->OutSec->Alignment);
+
+  // If neither AT nor AT> is specified for an allocatable section, the linker
+  // will set the LMA such that the difference between VMA and LMA for the
+  // section is the same as the preceding output section in the same region
+  // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
+  if (CurAddressState->LMAOffset)
+    CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset();
+}
+
+void LinkerScript::process(BaseCommand &Base) {
+  // This handles the assignments to symbol or to the dot.
+  if (auto *Cmd = dyn_cast<SymbolAssignment>(&Base)) {
+    assignSymbol(Cmd, true);
+    return;
+  }
+
+  // Handle BYTE(), SHORT(), LONG(), or QUAD().
+  if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) {
+    Cmd->Offset = Dot - CurAddressState->OutSec->Addr;
+    Dot += Cmd->Size;
+    CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
+    return;
+  }
+
+  // Handle ASSERT().
+  if (auto *Cmd = dyn_cast<AssertCommand>(&Base)) {
+    Cmd->Expression();
+    return;
+  }
+
+  // Handle a single input section description command.
+  // It calculates and assigns the offsets for each section and also
+  // updates the output section size.
+  auto &Cmd = cast<InputSectionDescription>(Base);
+  for (InputSection *Sec : Cmd.Sections) {
+    // We tentatively added all synthetic sections at the beginning and removed
+    // empty ones afterwards (because there is no way to know whether they were
+    // going be empty or not other than actually running linker scripts.)
+    // We need to ignore remains of empty sections.
+    if (auto *S = dyn_cast<SyntheticSection>(Sec))
+      if (S->empty())
+        continue;
+
+    if (!Sec->Live)
+      continue;
+    assert(CurAddressState->OutSec == Sec->getParent());
+    output(Sec);
+  }
+}
+
+// This function searches for a memory region to place the given output
+// section in. If found, a pointer to the appropriate memory region is
+// returned. Otherwise, a nullptr is returned.
+MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) {
+  // If a memory region name was specified in the output section command,
+  // then try to find that region first.
+  if (!Cmd->MemoryRegionName.empty()) {
+    auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName);
+    if (It != Opt.MemoryRegions.end())
+      return &It->second;
+    error("memory region '" + Cmd->MemoryRegionName + "' not declared");
+    return nullptr;
+  }
+
+  // If at least one memory region is defined, all sections must
+  // belong to some memory region. Otherwise, we don't need to do
+  // anything for memory regions.
+  if (Opt.MemoryRegions.empty())
+    return nullptr;
+
+  OutputSection *Sec = Cmd->Sec;
+  // See if a region can be found by matching section flags.
+  for (auto &Pair : Opt.MemoryRegions) {
+    MemoryRegion &M = Pair.second;
+    if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0)
+      return &M;
+  }
+
+  // Otherwise, no suitable region was found.
+  if (Sec->Flags & SHF_ALLOC)
+    error("no memory region specified for section '" + Sec->Name + "'");
+  return nullptr;
+}
+
+// This function assigns offsets to input sections and an output section
+// for a single sections command (e.g. ".text { *(.text); }").
+void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
+  OutputSection *Sec = Cmd->Sec;
+  if (!Sec)
+    return;
+
+  if (!(Sec->Flags & SHF_ALLOC))
+    Dot = 0;
+  else if (Cmd->AddrExpr)
+    setDot(Cmd->AddrExpr, Cmd->Location, false);
+
+  if (Cmd->LMAExpr) {
+    uint64_t D = Dot;
+    CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
+  }
+
+  CurAddressState->MemRegion = Cmd->MemRegion;
+  if (CurAddressState->MemRegion)
+    Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
+  switchTo(Sec);
+
+  // We do not support custom layout for compressed debug sectons.
+  // At this point we already know their size and have compressed content.
+  if (CurAddressState->OutSec->Flags & SHF_COMPRESSED)
+    return;
+
+  for (BaseCommand *C : Cmd->Commands)
+    process(*C);
+}
+
+void LinkerScript::removeEmptyCommands() {
+  // It is common practice to use very generic linker scripts. So for any
+  // given run some of the output sections in the script will be empty.
+  // We could create corresponding empty output sections, but that would
+  // clutter the output.
+  // We instead remove trivially empty sections. The bfd linker seems even
+  // more aggressive at removing them.
+  auto Pos = std::remove_if(
+      Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
+        if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+          return Cmd->Sec == nullptr;
+        return false;
+      });
+  Opt.Commands.erase(Pos, Opt.Commands.end());
+}
+
+static bool isAllSectionDescription(const OutputSectionCommand &Cmd) {
+  for (BaseCommand *Base : Cmd.Commands)
+    if (!isa<InputSectionDescription>(*Base))
+      return false;
+  return true;
+}
+
+void LinkerScript::adjustSectionsBeforeSorting() {
+  // If the output section contains only symbol assignments, create a
+  // corresponding output section. The bfd linker seems to only create them if
+  // '.' is assigned to, but creating these section should not have any bad
+  // consequeces and gives us a section to put the symbol in.
+  uint64_t Flags = SHF_ALLOC;
+
+  for (int I = 0, E = Opt.Commands.size(); I != E; ++I) {
+    auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
+    if (!Cmd)
+      continue;
+    if (OutputSection *Sec = Cmd->Sec) {
+      Flags = Sec->Flags;
+      continue;
+    }
+
+    if (isAllSectionDescription(*Cmd))
+      continue;
+
+    auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags);
+    OutSec->SectionIndex = I;
+    Cmd->Sec = OutSec;
+    SecToCommand[OutSec] = Cmd;
+  }
+}
+
+void LinkerScript::adjustSectionsAfterSorting() {
+  // Try and find an appropriate memory region to assign offsets in.
+  for (BaseCommand *Base : Opt.Commands) {
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) {
+      Cmd->MemRegion = findMemoryRegion(Cmd);
+      // Handle align (e.g. ".foo : ALIGN(16) { ... }").
+      if (Cmd->AlignExpr)
+        Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue());
+    }
+  }
+
+  // If output section command doesn't specify any segments,
+  // and we haven't previously assigned any section to segment,
+  // then we simply assign section to the very first load segment.
+  // Below is an example of such linker script:
+  // PHDRS { seg PT_LOAD; }
+  // SECTIONS { .aaa : { *(.aaa) } }
+  std::vector<StringRef> DefPhdrs;
+  auto FirstPtLoad =
+      std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(),
+                   [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; });
+  if (FirstPtLoad != Opt.PhdrsCommands.end())
+    DefPhdrs.push_back(FirstPtLoad->Name);
+
+  // Walk the commands and propagate the program headers to commands that don't
+  // explicitly specify them.
+  for (BaseCommand *Base : Opt.Commands) {
+    auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+    if (!Cmd)
+      continue;
+
+    if (Cmd->Phdrs.empty()) {
+      OutputSection *Sec = Cmd->Sec;
+      // To match the bfd linker script behaviour, only propagate program
+      // headers to sections that are allocated.
+      if (Sec && (Sec->Flags & SHF_ALLOC))
+        Cmd->Phdrs = DefPhdrs;
+    } else {
+      DefPhdrs = Cmd->Phdrs;
+    }
+  }
+
+  removeEmptyCommands();
+}
+
+void LinkerScript::processNonSectionCommands() {
+  for (BaseCommand *Base : Opt.Commands) {
+    if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
+      assignSymbol(Cmd, false);
+    else if (auto *Cmd = dyn_cast<AssertCommand>(Base))
+      Cmd->Expression();
+  }
+}
+
+void LinkerScript::allocateHeaders(std::vector<PhdrEntry> &Phdrs) {
+  uint64_t Min = std::numeric_limits<uint64_t>::max();
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec->Flags & SHF_ALLOC)
+      Min = std::min<uint64_t>(Min, Sec->Addr);
+  }
+
+  auto FirstPTLoad = llvm::find_if(
+      Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
+  if (FirstPTLoad == Phdrs.end())
+    return;
+
+  uint64_t HeaderSize = getHeaderSize();
+  if (HeaderSize <= Min || Script->hasPhdrsCommands()) {
+    Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
+    Out::ElfHeader->Addr = Min;
+    Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
+    return;
+  }
+
+  assert(FirstPTLoad->First == Out::ElfHeader);
+  OutputSection *ActualFirst = nullptr;
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec->FirstInPtLoad == Out::ElfHeader) {
+      ActualFirst = Sec;
+      break;
+    }
+  }
+  if (ActualFirst) {
+    for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+      OutputSection *Sec = Cmd->Sec;
+      if (Sec->FirstInPtLoad == Out::ElfHeader)
+        Sec->FirstInPtLoad = ActualFirst;
+    }
+    FirstPTLoad->First = ActualFirst;
+  } else {
+    Phdrs.erase(FirstPTLoad);
+  }
+
+  auto PhdrI = llvm::find_if(
+      Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; });
+  if (PhdrI != Phdrs.end())
+    Phdrs.erase(PhdrI);
+}
+
+LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) {
+  for (auto &MRI : Opt.MemoryRegions) {
+    const MemoryRegion *MR = &MRI.second;
+    MemRegionOffset[MR] = MR->Origin;
+  }
+}
+
+void LinkerScript::assignAddresses() {
+  // Assign addresses as instructed by linker script SECTIONS sub-commands.
+  Dot = 0;
+  auto State = make_unique<AddressState>(Opt);
+  // CurAddressState captures the local AddressState and makes it accessible
+  // deliberately. This is needed as there are some cases where we cannot just
+  // thread the current state through to a lambda function created by the
+  // script parser.
+  CurAddressState = State.get();
+  ErrorOnMissingSection = true;
+  switchTo(Aether);
+
+  for (BaseCommand *Base : Opt.Commands) {
+    if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+      assignSymbol(Cmd, false);
+      continue;
+    }
+
+    if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
+      Cmd->Expression();
+      continue;
+    }
+
+    auto *Cmd = cast<OutputSectionCommand>(Base);
+    assignOffsets(Cmd);
+  }
+  CurAddressState = nullptr;
+}
+
+// Creates program headers as instructed by PHDRS linker script command.
+std::vector<PhdrEntry> LinkerScript::createPhdrs() {
+  std::vector<PhdrEntry> Ret;
+
+  // Process PHDRS and FILEHDR keywords because they are not
+  // real output sections and cannot be added in the following loop.
+  for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) {
+    Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags);
+    PhdrEntry &Phdr = Ret.back();
+
+    if (Cmd.HasFilehdr)
+      Phdr.add(Out::ElfHeader);
+    if (Cmd.HasPhdrs)
+      Phdr.add(Out::ProgramHeaders);
+
+    if (Cmd.LMAExpr) {
+      Phdr.p_paddr = Cmd.LMAExpr().getValue();
+      Phdr.HasLMA = true;
+    }
+  }
+
+  // Add output sections to program headers.
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    // Assign headers specified by linker script
+    for (size_t Id : getPhdrIndices(Cmd)) {
+      OutputSection *Sec = Cmd->Sec;
+      Ret[Id].add(Sec);
+      if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
+        Ret[Id].p_flags |= Sec->getPhdrFlags();
+    }
+  }
+  return Ret;
+}
+
+bool LinkerScript::ignoreInterpSection() {
+  // Ignore .interp section in case we have PHDRS specification
+  // and PT_INTERP isn't listed.
+  if (Opt.PhdrsCommands.empty())
+    return false;
+  for (PhdrsCommand &Cmd : Opt.PhdrsCommands)
+    if (Cmd.Type == PT_INTERP)
+      return false;
+  return true;
+}
+
+OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
+  auto I = SecToCommand.find(Sec);
+  if (I == SecToCommand.end())
+    return nullptr;
+  return I->second;
+}
+
+void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) {
+  typedef std::pair<unsigned, InputSection *> Pair;
+  auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
+
+  std::vector<Pair> V;
+  assert(Commands.size() == 1);
+  auto *ISD = cast<InputSectionDescription>(Commands[0]);
+  for (InputSection *S : ISD->Sections)
+    V.push_back({Order(S), S});
+  std::stable_sort(V.begin(), V.end(), Comp);
+  ISD->Sections.clear();
+  for (Pair &P : V)
+    ISD->Sections.push_back(P.second);
+}
+
+// Returns true if S matches /Filename.?\.o$/.
+static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
+  if (!S.endswith(".o"))
+    return false;
+  S = S.drop_back(2);
+  if (S.endswith(Filename))
+    return true;
+  return !S.empty() && S.drop_back().endswith(Filename);
+}
+
+static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
+static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
+
+// .ctors and .dtors are sorted by this priority from highest to lowest.
+//
+//  1. The section was contained in crtbegin (crtbegin contains
+//     some sentinel value in its .ctors and .dtors so that the runtime
+//     can find the beginning of the sections.)
+//
+//  2. The section has an optional priority value in the form of ".ctors.N"
+//     or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
+//     they are compared as string rather than number.
+//
+//  3. The section is just ".ctors" or ".dtors".
+//
+//  4. The section was contained in crtend, which contains an end marker.
+//
+// In an ideal world, we don't need this function because .init_array and
+// .ctors are duplicate features (and .init_array is newer.) However, there
+// are too many real-world use cases of .ctors, so we had no choice to
+// support that with this rather ad-hoc semantics.
+static bool compCtors(const InputSection *A, const InputSection *B) {
+  bool BeginA = isCrtbegin(A->File->getName());
+  bool BeginB = isCrtbegin(B->File->getName());
+  if (BeginA != BeginB)
+    return BeginA;
+  bool EndA = isCrtend(A->File->getName());
+  bool EndB = isCrtend(B->File->getName());
+  if (EndA != EndB)
+    return EndB;
+  StringRef X = A->Name;
+  StringRef Y = B->Name;
+  assert(X.startswith(".ctors") || X.startswith(".dtors"));
+  assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
+  X = X.substr(6);
+  Y = Y.substr(6);
+  if (X.empty() && Y.empty())
+    return false;
+  return X < Y;
+}
+
+// Sorts input sections by the special rules for .ctors and .dtors.
+// Unfortunately, the rules are different from the one for .{init,fini}_array.
+// Read the comment above.
+void OutputSectionCommand::sortCtorsDtors() {
+  assert(Commands.size() == 1);
+  auto *ISD = cast<InputSectionDescription>(Commands[0]);
+  std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors);
+}
+
+// Sorts input sections by section name suffixes, so that .foo.N comes
+// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
+// We want to keep the original order if the priorities are the same
+// because the compiler keeps the original initialization order in a
+// translation unit and we need to respect that.
+// For more detail, read the section of the GCC's manual about init_priority.
+void OutputSectionCommand::sortInitFini() {
+  // Sort sections by priority.
+  sort([](InputSectionBase *S) { return getPriority(S->Name); });
+}
+
+uint32_t OutputSectionCommand::getFiller() {
+  if (Filler)
+    return *Filler;
+  if (Sec->Flags & SHF_EXECINSTR)
+    return Target->TrapInstr;
+  return 0;
+}
+
+static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
+  if (Size == 1)
+    *Buf = Data;
+  else if (Size == 2)
+    write16(Buf, Data, Config->Endianness);
+  else if (Size == 4)
+    write32(Buf, Data, Config->Endianness);
+  else if (Size == 8)
+    write64(Buf, Data, Config->Endianness);
+  else
+    llvm_unreachable("unsupported Size argument");
+}
+
+static bool compareByFilePosition(InputSection *A, InputSection *B) {
+  // Synthetic doesn't have link order dependecy, stable_sort will keep it last
+  if (A->kind() == InputSectionBase::Synthetic ||
+      B->kind() == InputSectionBase::Synthetic)
+    return false;
+  InputSection *LA = A->getLinkOrderDep();
+  InputSection *LB = B->getLinkOrderDep();
+  OutputSection *AOut = LA->getParent();
+  OutputSection *BOut = LB->getParent();
+  if (AOut != BOut)
+    return AOut->SectionIndex < BOut->SectionIndex;
+  return LA->OutSecOff < LB->OutSecOff;
+}
+
+template <class ELFT>
+static void finalizeShtGroup(OutputSection *OS,
+                             ArrayRef<InputSection *> Sections) {
+  assert(Config->Relocatable && Sections.size() == 1);
+
+  // sh_link field for SHT_GROUP sections should contain the section index of
+  // the symbol table.
+  OS->Link = InX::SymTab->getParent()->SectionIndex;
+
+  // sh_info then contain index of an entry in symbol table section which
+  // provides signature of the section group.
+  elf::ObjectFile<ELFT> *Obj = Sections[0]->getFile<ELFT>();
+  ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
+  OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]);
+}
+
+template <class ELFT> void OutputSectionCommand::finalize() {
+  // Link order may be distributed across several InputSectionDescriptions
+  // but sort must consider them all at once.
+  std::vector<InputSection **> ScriptSections;
+  std::vector<InputSection *> Sections;
+  for (BaseCommand *Base : Commands)
+    if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+      for (InputSection *&IS : ISD->Sections) {
+        ScriptSections.push_back(&IS);
+        Sections.push_back(IS);
+      }
+
+  if ((Sec->Flags & SHF_LINK_ORDER)) {
+    std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition);
+    for (int I = 0, N = Sections.size(); I < N; ++I)
+      *ScriptSections[I] = Sections[I];
+
+    // We must preserve the link order dependency of sections with the
+    // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
+    // need to translate the InputSection sh_link to the OutputSection sh_link,
+    // all InputSections in the OutputSection have the same dependency.
+    if (auto *D = Sections.front()->getLinkOrderDep())
+      Sec->Link = D->getParent()->SectionIndex;
+  }
+
+  uint32_t Type = Sec->Type;
+  if (Type == SHT_GROUP) {
+    finalizeShtGroup<ELFT>(Sec, Sections);
+    return;
+  }
+
+  if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
+    return;
+
+  InputSection *First = Sections[0];
+  if (isa<SyntheticSection>(First))
+    return;
+
+  Sec->Link = InX::SymTab->getParent()->SectionIndex;
+  // sh_info for SHT_REL[A] sections should contain the section header index of
+  // the section to which the relocation applies.
+  InputSectionBase *S = First->getRelocatedSection();
+  Sec->Info = S->getOutputSection()->SectionIndex;
+  Sec->Flags |= SHF_INFO_LINK;
+}
+
+// Compress section contents if this section contains debug info.
+template <class ELFT> void OutputSectionCommand::maybeCompress() {
+  typedef typename ELFT::Chdr Elf_Chdr;
+
+  // Compress only DWARF debug sections.
+  if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) ||
+      !Name.startswith(".debug_"))
+    return;
+
+  // Create a section header.
+  Sec->ZDebugHeader.resize(sizeof(Elf_Chdr));
+  auto *Hdr = reinterpret_cast<Elf_Chdr *>(Sec->ZDebugHeader.data());
+  Hdr->ch_type = ELFCOMPRESS_ZLIB;
+  Hdr->ch_size = Sec->Size;
+  Hdr->ch_addralign = Sec->Alignment;
+
+  // Write section contents to a temporary buffer and compress it.
+  std::vector<uint8_t> Buf(Sec->Size);
+  writeTo<ELFT>(Buf.data());
+  if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData))
+    fatal("compress failed: " + llvm::toString(std::move(E)));
+
+  // Update section headers.
+  Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size();
+  Sec->Flags |= SHF_COMPRESSED;
+}
+
+template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
+  if (Sec->Type == SHT_NOBITS)
+    return;
+
+  Sec->Loc = Buf;
+
+  // If -compress-debug-section is specified and if this is a debug seciton,
+  // we've already compressed section contents. If that's the case,
+  // just write it down.
+  if (!Sec->CompressedData.empty()) {
+    memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size());
+    memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(),
+           Sec->CompressedData.size());
+    return;
+  }
+
+  // Write leading padding.
+  std::vector<InputSection *> Sections;
+  for (BaseCommand *Cmd : Commands)
+    if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+      for (InputSection *IS : ISD->Sections)
+        if (IS->Live)
+          Sections.push_back(IS);
+  uint32_t Filler = getFiller();
+  if (Filler)
+    fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler);
+
+  parallelForEachN(0, Sections.size(), [=](size_t I) {
+    InputSection *IS = Sections[I];
+    IS->writeTo<ELFT>(Buf);
+
+    // Fill gaps between sections.
+    if (Filler) {
+      uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
+      uint8_t *End;
+      if (I + 1 == Sections.size())
+        End = Buf + Sec->Size;
+      else
+        End = Buf + Sections[I + 1]->OutSecOff;
+      fill(Start, End - Start, Filler);
+    }
+  });
+
+  // Linker scripts may have BYTE()-family commands with which you
+  // can write arbitrary bytes to the output. Process them if any.
+  for (BaseCommand *Base : Commands)
+    if (auto *Data = dyn_cast<BytesDataCommand>(Base))
+      writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
+}
+
+ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
+  if (S == ".")
+    return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc};
+  if (SymbolBody *B = findSymbol(S)) {
+    if (auto *D = dyn_cast<DefinedRegular>(B))
+      return {D->Section, D->Value, Loc};
+    if (auto *C = dyn_cast<DefinedCommon>(B))
+      return {InX::Common, C->Offset, Loc};
+  }
+  error(Loc + ": symbol not found: " + S);
+  return 0;
+}
+
+bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; }
+
+static const size_t NoPhdr = -1;
+
+// Returns indices of ELF headers containing specific section. Each index is a
+// zero based number of ELF header listed within PHDRS {} script block.
+std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) {
+  std::vector<size_t> Ret;
+  for (StringRef PhdrName : Cmd->Phdrs) {
+    size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
+    if (Index != NoPhdr)
+      Ret.push_back(Index);
+  }
+  return Ret;
+}
+
+// Returns the index of the segment named PhdrName if found otherwise
+// NoPhdr. When not found, if PhdrName is not the special case value 'NONE'
+// (which can be used to explicitly specify that a section isn't assigned to a
+// segment) then error.
+size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
+  size_t I = 0;
+  for (PhdrsCommand &Cmd : Opt.PhdrsCommands) {
+    if (Cmd.Name == PhdrName)
+      return I;
+    ++I;
+  }
+  if (PhdrName != "NONE")
+    error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
+  return NoPhdr;
+}
+
+template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf);
+
+template void OutputSectionCommand::maybeCompress<ELF32LE>();
+template void OutputSectionCommand::maybeCompress<ELF32BE>();
+template void OutputSectionCommand::maybeCompress<ELF64LE>();
+template void OutputSectionCommand::maybeCompress<ELF64BE>();
+
+template void OutputSectionCommand::finalize<ELF32LE>();
+template void OutputSectionCommand::finalize<ELF32BE>();
+template void OutputSectionCommand::finalize<ELF64LE>();
+template void OutputSectionCommand::finalize<ELF64BE>();
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
new file mode 100644 (file)
index 0000000..dd5a7d7
--- /dev/null
@@ -0,0 +1,306 @@
+//===- LinkerScript.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_LINKER_SCRIPT_H
+#define LLD_ELF_LINKER_SCRIPT_H
+
+#include "Config.h"
+#include "Strings.h"
+#include "Writer.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class DefinedCommon;
+class SymbolBody;
+class InputSectionBase;
+class InputSection;
+class OutputSection;
+class OutputSectionFactory;
+class InputSectionBase;
+class SectionBase;
+
+struct ExprValue {
+  SectionBase *Sec;
+  uint64_t Val;
+  bool ForceAbsolute;
+  uint64_t Alignment = 1;
+  std::string Loc;
+
+  ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val,
+            const Twine &Loc)
+      : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Loc(Loc.str()) {}
+  ExprValue(SectionBase *Sec, uint64_t Val, const Twine &Loc)
+      : ExprValue(Sec, false, Val, Loc) {}
+  ExprValue(uint64_t Val) : ExprValue(nullptr, Val, "") {}
+  bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; }
+  uint64_t getValue() const;
+  uint64_t getSecAddr() const;
+};
+
+// This represents an expression in the linker script.
+// ScriptParser::readExpr reads an expression and returns an Expr.
+// Later, we evaluate the expression by calling the function.
+typedef std::function<ExprValue()> Expr;
+
+// This enum is used to implement linker script SECTIONS command.
+// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
+enum SectionsCommandKind {
+  AssignmentKind, // . = expr or <sym> = expr
+  OutputSectionKind,
+  InputSectionKind,
+  AssertKind,   // ASSERT(expr)
+  BytesDataKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr)
+};
+
+struct BaseCommand {
+  BaseCommand(int K) : Kind(K) {}
+  int Kind;
+};
+
+// This represents ". = <expr>" or "<symbol> = <expr>".
+struct SymbolAssignment : BaseCommand {
+  SymbolAssignment(StringRef Name, Expr E, std::string Loc)
+      : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {}
+
+  static bool classof(const BaseCommand *C);
+
+  // The LHS of an expression. Name is either a symbol name or ".".
+  StringRef Name;
+  SymbolBody *Sym = nullptr;
+
+  // The RHS of an expression.
+  Expr Expression;
+
+  // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN.
+  bool Provide = false;
+  bool Hidden = false;
+
+  // Holds file name and line number for error reporting.
+  std::string Location;
+};
+
+// Linker scripts allow additional constraints to be put on ouput sections.
+// If an output section is marked as ONLY_IF_RO, the section is created
+// only if its input sections are read-only. Likewise, an output section
+// with ONLY_IF_RW is created if all input sections are RW.
+enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
+
+// This struct is used to represent the location and size of regions of
+// target memory. Instances of the struct are created by parsing the
+// MEMORY command.
+struct MemoryRegion {
+  std::string Name;
+  uint64_t Origin;
+  uint64_t Length;
+  uint32_t Flags;
+  uint32_t NegFlags;
+};
+
+struct OutputSectionCommand : BaseCommand {
+  OutputSectionCommand(StringRef Name)
+      : BaseCommand(OutputSectionKind), Name(Name) {}
+
+  static bool classof(const BaseCommand *C);
+
+  OutputSection *Sec = nullptr;
+  MemoryRegion *MemRegion = nullptr;
+  StringRef Name;
+  Expr AddrExpr;
+  Expr AlignExpr;
+  Expr LMAExpr;
+  Expr SubalignExpr;
+  std::vector<BaseCommand *> Commands;
+  std::vector<StringRef> Phdrs;
+  llvm::Optional<uint32_t> Filler;
+  ConstraintKind Constraint = ConstraintKind::NoConstraint;
+  std::string Location;
+  std::string MemoryRegionName;
+  bool Noload = false;
+
+  template <class ELFT> void finalize();
+  template <class ELFT> void writeTo(uint8_t *Buf);
+  template <class ELFT> void maybeCompress();
+  uint32_t getFiller();
+
+  void sort(std::function<int(InputSectionBase *S)> Order);
+  void sortInitFini();
+  void sortCtorsDtors();
+};
+
+// This struct represents one section match pattern in SECTIONS() command.
+// It can optionally have negative match pattern for EXCLUDED_FILE command.
+// Also it may be surrounded with SORT() command, so contains sorting rules.
+struct SectionPattern {
+  SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2)
+      : ExcludedFilePat(Pat1), SectionPat(Pat2) {}
+
+  StringMatcher ExcludedFilePat;
+  StringMatcher SectionPat;
+  SortSectionPolicy SortOuter;
+  SortSectionPolicy SortInner;
+};
+
+struct InputSectionDescription : BaseCommand {
+  InputSectionDescription(StringRef FilePattern)
+      : BaseCommand(InputSectionKind), FilePat(FilePattern) {}
+
+  static bool classof(const BaseCommand *C);
+
+  StringMatcher FilePat;
+
+  // Input sections that matches at least one of SectionPatterns
+  // will be associated with this InputSectionDescription.
+  std::vector<SectionPattern> SectionPatterns;
+
+  std::vector<InputSection *> Sections;
+};
+
+// Represents an ASSERT().
+struct AssertCommand : BaseCommand {
+  AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {}
+
+  static bool classof(const BaseCommand *C);
+
+  Expr Expression;
+};
+
+// Represents BYTE(), SHORT(), LONG(), or QUAD().
+struct BytesDataCommand : BaseCommand {
+  BytesDataCommand(Expr E, unsigned Size)
+      : BaseCommand(BytesDataKind), Expression(E), Size(Size) {}
+
+  static bool classof(const BaseCommand *C);
+
+  Expr Expression;
+  unsigned Offset;
+  unsigned Size;
+};
+
+struct PhdrsCommand {
+  StringRef Name;
+  unsigned Type;
+  bool HasFilehdr;
+  bool HasPhdrs;
+  unsigned Flags;
+  Expr LMAExpr;
+};
+
+// ScriptConfiguration holds linker script parse results.
+struct ScriptConfiguration {
+  // Used to assign addresses to sections.
+  std::vector<BaseCommand *> Commands;
+
+  // Used to assign sections to headers.
+  std::vector<PhdrsCommand> PhdrsCommands;
+
+  bool HasSections = false;
+
+  // List of section patterns specified with KEEP commands. They will
+  // be kept even if they are unused and --gc-sections is specified.
+  std::vector<InputSectionDescription *> KeptSections;
+
+  // A map from memory region name to a memory region descriptor.
+  llvm::DenseMap<llvm::StringRef, MemoryRegion> MemoryRegions;
+
+  // A list of symbols referenced by the script.
+  std::vector<llvm::StringRef> ReferencedSymbols;
+};
+
+class LinkerScript final {
+  // Temporary state used in processCommands() and assignAddresses()
+  // that must be reinitialized for each call to the above functions, and must
+  // not be used outside of the scope of a call to the above functions.
+  struct AddressState {
+    uint64_t ThreadBssOffset = 0;
+    OutputSection *OutSec = nullptr;
+    MemoryRegion *MemRegion = nullptr;
+    llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset;
+    std::function<uint64_t()> LMAOffset;
+    AddressState(const ScriptConfiguration &Opt);
+  };
+  llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
+  llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand;
+
+  void assignSymbol(SymbolAssignment *Cmd, bool InSec);
+  void setDot(Expr E, const Twine &Loc, bool InSec);
+
+  std::vector<InputSection *>
+  computeInputSections(const InputSectionDescription *);
+
+  std::vector<InputSectionBase *>
+  createInputSectionList(OutputSectionCommand &Cmd);
+
+  std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd);
+  size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
+
+  MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
+
+  void switchTo(OutputSection *Sec);
+  uint64_t advance(uint64_t Size, unsigned Align);
+  void output(InputSection *Sec);
+  void process(BaseCommand &Base);
+
+  AddressState *CurAddressState = nullptr;
+  OutputSection *Aether;
+
+  uint64_t Dot;
+
+public:
+  bool ErrorOnMissingSection = false;
+  OutputSectionCommand *createOutputSectionCommand(StringRef Name,
+                                                   StringRef Location);
+  OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name);
+
+  OutputSectionCommand *getCmd(OutputSection *Sec) const;
+  bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
+  uint64_t getDot() { return Dot; }
+  void discard(ArrayRef<InputSectionBase *> V);
+
+  ExprValue getSymbolValue(const Twine &Loc, StringRef S);
+  bool isDefined(StringRef S);
+
+  void fabricateDefaultCommands();
+  void addOrphanSections(OutputSectionFactory &Factory);
+  void removeEmptyCommands();
+  void adjustSectionsBeforeSorting();
+  void adjustSectionsAfterSorting();
+
+  std::vector<PhdrEntry> createPhdrs();
+  bool ignoreInterpSection();
+
+  bool shouldKeep(InputSectionBase *S);
+  void assignOffsets(OutputSectionCommand *Cmd);
+  void processNonSectionCommands();
+  void assignAddresses();
+  void allocateHeaders(std::vector<PhdrEntry> &Phdrs);
+  void addSymbol(SymbolAssignment *Cmd);
+  void processCommands(OutputSectionFactory &Factory);
+
+  // Parsed linker script configurations are set to this struct.
+  ScriptConfiguration Opt;
+};
+
+extern LinkerScript *Script;
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // LLD_ELF_LINKER_SCRIPT_H
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
new file mode 100644 (file)
index 0000000..2b2a95c
--- /dev/null
@@ -0,0 +1,150 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the -Map option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+//   Address  Size     Align Out     In      Symbol
+//   00201000 00000015     4 .text
+//   00201000 0000000e     4         test.o:(.text)
+//   0020100e 00000000     0                 local
+//   00201005 00000000     0                 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Threads.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+typedef DenseMap<const SectionBase *, SmallVector<DefinedRegular *, 4>>
+    SymbolMapTy;
+
+// Print out the first three columns of a line.
+template <class ELFT>
+static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
+                        uint64_t Align) {
+  int W = ELFT::Is64Bits ? 16 : 8;
+  OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
+}
+
+static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
+
+// Returns a list of all symbols that we want to print out.
+template <class ELFT> std::vector<DefinedRegular *> getSymbols() {
+  std::vector<DefinedRegular *> V;
+  for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles())
+    for (SymbolBody *B : File->getSymbols())
+      if (B->File == File && !B->isSection())
+        if (auto *Sym = dyn_cast<DefinedRegular>(B))
+          if (Sym->Section && Sym->Section->Live)
+            V.push_back(Sym);
+  return V;
+}
+
+// Returns a map from sections to their symbols.
+template <class ELFT>
+SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
+  SymbolMapTy Ret;
+  for (DefinedRegular *S : Syms)
+    Ret[S->Section].push_back(S);
+
+  // Sort symbols by address. We want to print out symbols in the
+  // order in the output file rather than the order they appeared
+  // in the input files.
+  for (auto &It : Ret) {
+    SmallVectorImpl<DefinedRegular *> &V = It.second;
+    std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
+      return A->getVA() < B->getVA();
+    });
+  }
+  return Ret;
+}
+
+// Construct a map from symbols to their stringified representations.
+// Demangling symbols (which is what toString() does) is slow, so
+// we do that in batch using parallel-for.
+template <class ELFT>
+DenseMap<DefinedRegular *, std::string>
+getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
+  std::vector<std::string> Str(Syms.size());
+  parallelForEachN(0, Syms.size(), [&](size_t I) {
+    raw_string_ostream OS(Str[I]);
+    writeHeader<ELFT>(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(),
+                      0);
+    OS << indent(2) << toString(*Syms[I]);
+  });
+
+  DenseMap<DefinedRegular *, std::string> Ret;
+  for (size_t I = 0, E = Syms.size(); I < E; ++I)
+    Ret[Syms[I]] = std::move(Str[I]);
+  return Ret;
+}
+
+template <class ELFT>
+void elf::writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script) {
+  if (Config->MapFile.empty())
+    return;
+
+  // Open a map file for writing.
+  std::error_code EC;
+  raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+  if (EC) {
+    error("cannot open " + Config->MapFile + ": " + EC.message());
+    return;
+  }
+
+  // Collect symbol info that we want to print out.
+  std::vector<DefinedRegular *> Syms = getSymbols<ELFT>();
+  SymbolMapTy SectionSyms = getSectionSyms<ELFT>(Syms);
+  DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings<ELFT>(Syms);
+
+  // Print out the header line.
+  int W = ELFT::Is64Bits ? 16 : 8;
+  OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
+     << " Align Out     In      Symbol\n";
+
+  // Print out file contents.
+  for (OutputSectionCommand *Cmd : Script) {
+    OutputSection *OSec = Cmd->Sec;
+    writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment);
+    OS << OSec->Name << '\n';
+
+    // Dump symbols for each input section.
+    for (BaseCommand *Base : Cmd->Commands) {
+      auto *ISD = dyn_cast<InputSectionDescription>(Base);
+      if (!ISD)
+        continue;
+      for (InputSection *IS : ISD->Sections) {
+        writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
+                          IS->Alignment);
+        OS << indent(1) << toString(IS) << '\n';
+        for (DefinedRegular *Sym : SectionSyms[IS])
+          OS << SymStr[Sym] << '\n';
+      }
+    }
+  }
+}
+
+template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSectionCommand *>);
+template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSectionCommand *>);
+template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSectionCommand *>);
+template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSectionCommand *>);
diff --git a/ELF/MapFile.h b/ELF/MapFile.h
new file mode 100644 (file)
index 0000000..460848f
--- /dev/null
@@ -0,0 +1,23 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MAPFILE_H
+#define LLD_ELF_MAPFILE_H
+
+#include <llvm/ADT/ArrayRef.h>
+
+namespace lld {
+namespace elf {
+struct OutputSectionCommand;
+template <class ELFT>
+void writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
new file mode 100644 (file)
index 0000000..bde3eef
--- /dev/null
@@ -0,0 +1,268 @@
+//===- MarkLive.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements --gc-sections, which is a feature to remove unused
+// sections from output. Unused sections are sections that are not reachable
+// from known GC-root symbols or sections. Naturally the feature is
+// implemented as a mark-sweep garbage collector.
+//
+// Here's how it works. Each InputSectionBase has a "Live" bit. The bit is off
+// by default. Starting with GC-root symbols or sections, markLive function
+// defined in this file visits all reachable sections to set their Live
+// bits. Writer will then ignore sections whose Live bits are off, so that
+// such sections are not included into output.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "Writer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/ELF.h"
+#include <functional>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+// A resolved relocation. The Sec and Offset fields are set if the relocation
+// was resolved to an offset within a section.
+struct ResolvedReloc {
+  InputSectionBase *Sec;
+  uint64_t Offset;
+};
+} // end anonymous namespace
+
+template <class ELFT>
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
+                                     const typename ELFT::Rel &Rel) {
+  return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
+                                   Rel.getType(Config->IsMips64EL));
+}
+
+template <class ELFT>
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
+                                     const typename ELFT::Rela &Rel) {
+  return Rel.r_addend;
+}
+
+// There are normally few input sections whose names are valid C
+// identifiers, so we just store a std::vector instead of a multimap.
+static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
+
+template <class ELFT, class RelT>
+static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
+                         std::function<void(ResolvedReloc)> Fn) {
+  SymbolBody &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+  if (auto *D = dyn_cast<DefinedRegular>(&B)) {
+    if (!D->Section)
+      return;
+    typename ELFT::uint Offset = D->Value;
+    if (D->isSection())
+      Offset += getAddend<ELFT>(Sec, Rel);
+    Fn({cast<InputSectionBase>(D->Section), Offset});
+  } else if (auto *U = dyn_cast<Undefined>(&B)) {
+    for (InputSectionBase *Sec : CNamedSections.lookup(U->getName()))
+      Fn({Sec, 0});
+  }
+}
+
+// Calls Fn for each section that Sec refers to via relocations.
+template <class ELFT>
+static void forEachSuccessor(InputSection &Sec,
+                             std::function<void(ResolvedReloc)> Fn) {
+  if (Sec.AreRelocsRela) {
+    for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
+      resolveReloc<ELFT>(Sec, Rel, Fn);
+  } else {
+    for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>())
+      resolveReloc<ELFT>(Sec, Rel, Fn);
+  }
+  for (InputSectionBase *IS : Sec.DependentSections)
+    Fn({IS, 0});
+}
+
+// The .eh_frame section is an unfortunate special case.
+// The section is divided in CIEs and FDEs and the relocations it can have are
+// * CIEs can refer to a personality function.
+// * FDEs can refer to a LSDA
+// * FDEs refer to the function they contain information about
+// The last kind of relocation cannot keep the referred section alive, or they
+// would keep everything alive in a common object file. In fact, each FDE is
+// alive if the section it refers to is alive.
+// To keep things simple, in here we just ignore the last relocation kind. The
+// other two keep the referred section alive.
+//
+// A possible improvement would be to fully process .eh_frame in the middle of
+// the gc pass. With that we would be able to also gc some sections holding
+// LSDAs and personality functions if we found that they were unused.
+template <class ELFT, class RelTy>
+static void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
+                               std::function<void(ResolvedReloc)> Enqueue) {
+  const endianness E = ELFT::TargetEndianness;
+  for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
+    EhSectionPiece &Piece = EH.Pieces[I];
+    unsigned FirstRelI = Piece.FirstRelocation;
+    if (FirstRelI == (unsigned)-1)
+      continue;
+    if (read32<E>(Piece.data().data() + 4) == 0) {
+      // This is a CIE, we only need to worry about the first relocation. It is
+      // known to point to the personality function.
+      resolveReloc<ELFT>(EH, Rels[FirstRelI], Enqueue);
+      continue;
+    }
+    // This is a FDE. The relocations point to the described function or to
+    // a LSDA. We only need to keep the LSDA alive, so ignore anything that
+    // points to executable sections.
+    typename ELFT::uint PieceEnd = Piece.InputOff + Piece.size();
+    for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) {
+      const RelTy &Rel = Rels[I2];
+      if (Rel.r_offset >= PieceEnd)
+        break;
+      resolveReloc<ELFT>(EH, Rels[I2], [&](ResolvedReloc R) {
+        if (!R.Sec || R.Sec == &InputSection::Discarded)
+          return;
+        if (R.Sec->Flags & SHF_EXECINSTR)
+          return;
+        Enqueue({R.Sec, 0});
+      });
+    }
+  }
+}
+
+template <class ELFT>
+static void scanEhFrameSection(EhInputSection &EH,
+                               std::function<void(ResolvedReloc)> Enqueue) {
+  if (!EH.NumRelocations)
+    return;
+
+  // Unfortunately we need to split .eh_frame early since some relocations in
+  // .eh_frame keep other section alive and some don't.
+  EH.split<ELFT>();
+
+  if (EH.AreRelocsRela)
+    scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Enqueue);
+  else
+    scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Enqueue);
+}
+
+// We do not garbage-collect two types of sections:
+// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr)
+// 2) Non-allocatable sections which typically contain debugging information
+template <class ELFT> static bool isReserved(InputSectionBase *Sec) {
+  switch (Sec->Type) {
+  case SHT_FINI_ARRAY:
+  case SHT_INIT_ARRAY:
+  case SHT_NOTE:
+  case SHT_PREINIT_ARRAY:
+    return true;
+  default:
+    if (!(Sec->Flags & SHF_ALLOC))
+      return true;
+
+    StringRef S = Sec->Name;
+    return S.startswith(".ctors") || S.startswith(".dtors") ||
+           S.startswith(".init") || S.startswith(".fini") ||
+           S.startswith(".jcr");
+  }
+}
+
+// This is the main function of the garbage collector.
+// Starting from GC-root sections, this function visits all reachable
+// sections to set their "Live" bits.
+template <class ELFT> void elf::markLive() {
+  SmallVector<InputSection *, 256> Q;
+  CNamedSections.clear();
+
+  auto Enqueue = [&](ResolvedReloc R) {
+    // Skip over discarded sections. This in theory shouldn't happen, because
+    // the ELF spec doesn't allow a relocation to point to a deduplicated
+    // COMDAT section directly. Unfortunately this happens in practice (e.g.
+    // .eh_frame) so we need to add a check.
+    if (R.Sec == &InputSection::Discarded)
+      return;
+
+    // We don't gc non alloc sections.
+    if (!(R.Sec->Flags & SHF_ALLOC))
+      return;
+
+    // Usually, a whole section is marked as live or dead, but in mergeable
+    // (splittable) sections, each piece of data has independent liveness bit.
+    // So we explicitly tell it which offset is in use.
+    if (auto *MS = dyn_cast<MergeInputSection>(R.Sec))
+      MS->markLiveAt(R.Offset);
+
+    if (R.Sec->Live)
+      return;
+    R.Sec->Live = true;
+    // Add input section to the queue.
+    if (InputSection *S = dyn_cast<InputSection>(R.Sec))
+      Q.push_back(S);
+  };
+
+  auto MarkSymbol = [&](const SymbolBody *Sym) {
+    if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym))
+      if (auto *IS = cast_or_null<InputSectionBase>(D->Section))
+        Enqueue({IS, D->Value});
+  };
+
+  // Add GC root symbols.
+  MarkSymbol(Symtab<ELFT>::X->find(Config->Entry));
+  MarkSymbol(Symtab<ELFT>::X->find(Config->Init));
+  MarkSymbol(Symtab<ELFT>::X->find(Config->Fini));
+  for (StringRef S : Config->Undefined)
+    MarkSymbol(Symtab<ELFT>::X->find(S));
+  for (StringRef S : Script->Opt.ReferencedSymbols)
+    MarkSymbol(Symtab<ELFT>::X->find(S));
+
+  // Preserve externally-visible symbols if the symbols defined by this
+  // file can interrupt other ELF file's symbols at runtime.
+  for (const Symbol *S : Symtab<ELFT>::X->getSymbols())
+    if (S->includeInDynsym())
+      MarkSymbol(S->body());
+
+  // Preserve special sections and those which are specified in linker
+  // script KEEP command.
+  for (InputSectionBase *Sec : InputSections) {
+    // .eh_frame is always marked as live now, but also it can reference to
+    // sections that contain personality. We preserve all non-text sections
+    // referred by .eh_frame here.
+    if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec))
+      scanEhFrameSection<ELFT>(*EH, Enqueue);
+    if (Sec->Flags & SHF_LINK_ORDER)
+      continue;
+    if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec))
+      Enqueue({Sec, 0});
+    else if (isValidCIdentifier(Sec->Name)) {
+      CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
+      CNamedSections[Saver.save("__end_" + Sec->Name)].push_back(Sec);
+    }
+  }
+
+  // Mark all reachable sections.
+  while (!Q.empty())
+    forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue);
+}
+
+template void elf::markLive<ELF32LE>();
+template void elf::markLive<ELF32BE>();
+template void elf::markLive<ELF64LE>();
+template void elf::markLive<ELF64BE>();
diff --git a/ELF/Memory.h b/ELF/Memory.h
new file mode 100644 (file)
index 0000000..4000f2f
--- /dev/null
@@ -0,0 +1,67 @@
+//===- Memory.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines arena allocators.
+//
+// Almost all large objects, such as files, sections or symbols, are
+// used for the entire lifetime of the linker once they are created.
+// This usage characteristic makes arena allocator an attractive choice
+// where the entire linker is one arena. With an arena, newly created
+// objects belong to the arena and freed all at once when everything is done.
+// Arena allocators are efficient and easy to understand.
+// Most objects are allocated using the arena allocators defined by this file.
+//
+// If you edit this file, please edit COFF/Memory.h too.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MEMORY_H
+#define LLD_ELF_MEMORY_H
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/StringSaver.h"
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+// Use this arena if your object doesn't have a destructor.
+extern llvm::BumpPtrAllocator BAlloc;
+extern llvm::StringSaver Saver;
+
+// These two classes are hack to keep track of all
+// SpecificBumpPtrAllocator instances.
+struct SpecificAllocBase {
+  SpecificAllocBase() { Instances.push_back(this); }
+  virtual ~SpecificAllocBase() = default;
+  virtual void reset() = 0;
+  static std::vector<SpecificAllocBase *> Instances;
+};
+
+template <class T> struct SpecificAlloc : public SpecificAllocBase {
+  void reset() override { Alloc.DestroyAll(); }
+  llvm::SpecificBumpPtrAllocator<T> Alloc;
+};
+
+// Use this arena if your object has a destructor.
+// Your destructor will be invoked from freeArena().
+template <typename T, typename... U> T *make(U &&... Args) {
+  static SpecificAlloc<T> Alloc;
+  return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
+}
+
+inline void freeArena() {
+  for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
+    Alloc->reset();
+  BAlloc.Reset();
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Options.td b/ELF/Options.td
new file mode 100644 (file)
index 0000000..1400a20
--- /dev/null
@@ -0,0 +1,414 @@
+include "llvm/Option/OptParser.td"
+
+// For options whose names are multiple letters, either one dash or
+// two can precede the option name except those that start with 'o'.
+class F<string name>: Flag<["--", "-"], name>;
+class J<string name>: Joined<["--", "-"], name>;
+class S<string name>: Separate<["--", "-"], name>;
+class JS<string name>: JoinedOrSeparate<["--", "-"], name>;
+
+def auxiliary: S<"auxiliary">, HelpText<"Set DT_AUXILIARY field to the specified name">;
+
+def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
+
+def Bsymbolic_functions: F<"Bsymbolic-functions">,
+  HelpText<"Bind defined function symbols locally">;
+
+def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
+
+def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
+
+def build_id: F<"build-id">, HelpText<"Generate build ID note">;
+
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+
+def compress_debug_sections : J<"compress-debug-sections=">,
+  HelpText<"Compress DWARF debug sections">;
+
+def defsym: J<"defsym=">, HelpText<"Define a symbol alias">;
+
+def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+  HelpText<"Add a directory to the library search path">;
+
+def O: Joined<["-"], "O">, HelpText<"Optimize output file size">;
+
+def Tbss: S<"Tbss">, HelpText<"Same as --section-start with .bss as the sectionname">;
+
+def Tdata: S<"Tdata">, HelpText<"Same as --section-start with .data as the sectionname">;
+
+def Ttext: S<"Ttext">, HelpText<"Same as --section-start with .text as the sectionname">;
+
+def allow_multiple_definition: F<"allow-multiple-definition">,
+  HelpText<"Allow multiple definitions">;
+
+def as_needed: F<"as-needed">,
+  HelpText<"Only set DT_NEEDED for shared libraries if used">;
+
+def color_diagnostics: F<"color-diagnostics">,
+  HelpText<"Use colors in diagnostics">;
+
+def color_diagnostics_eq: J<"color-diagnostics=">,
+  HelpText<"Use colors in diagnostics">;
+
+def define_common: F<"define-common">,
+  HelpText<"Assign space to common symbols">;
+
+def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
+
+def disable_new_dtags: F<"disable-new-dtags">,
+  HelpText<"Disable new dynamic tags">;
+
+def discard_all: F<"discard-all">, HelpText<"Delete all local symbols">;
+
+def discard_locals: F<"discard-locals">,
+  HelpText<"Delete temporary local symbols">;
+
+def discard_none: F<"discard-none">,
+  HelpText<"Keep all symbols in the symbol table">;
+
+def dynamic_linker: S<"dynamic-linker">,
+  HelpText<"Which dynamic linker to use">;
+
+def dynamic_list: S<"dynamic-list">,
+  HelpText<"Read a list of dynamic symbols">;
+
+def eh_frame_hdr: F<"eh-frame-hdr">,
+  HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+
+def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
+
+def enable_new_dtags: F<"enable-new-dtags">,
+  HelpText<"Enable new dynamic tags">;
+
+def end_lib: F<"end-lib">,
+  HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
+
+def entry: S<"entry">, MetaVarName<"<entry>">,
+  HelpText<"Name of entry point symbol">;
+
+def error_limit: S<"error-limit">,
+  HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+
+def error_unresolved_symbols: F<"error-unresolved-symbols">,
+  HelpText<"Report unresolved symbols as errors">;
+
+def exclude_libs: S<"exclude-libs">,
+  HelpText<"Exclude static libraries from automatic export">;
+
+def export_dynamic: F<"export-dynamic">,
+  HelpText<"Put symbols in the dynamic symbol table">;
+
+def export_dynamic_symbol: S<"export-dynamic-symbol">,
+  HelpText<"Put a symbol in the dynamic symbol table">;
+
+def fatal_warnings: F<"fatal-warnings">,
+  HelpText<"Treat warnings as errors">;
+
+def filter: J<"filter=">, HelpText<"Set DT_FILTER field to the specified name">;
+
+def fini: S<"fini">, MetaVarName<"<symbol>">,
+  HelpText<"Specify a finalizer function">;
+
+def full_shutdown : F<"full-shutdown">,
+  HelpText<"Perform a full shutdown instead of calling _exit">;
+
+def format: J<"format=">, MetaVarName<"<input-format>">,
+  HelpText<"Change the input format of the inputs following this option">;
+
+def gc_sections: F<"gc-sections">,
+  HelpText<"Enable garbage collection of unused sections">;
+
+def gdb_index: F<"gdb-index">,
+  HelpText<"Generate .gdb_index section">;
+
+def hash_style: S<"hash-style">,
+  HelpText<"Specify hash style (sysv, gnu or both)">;
+
+def help: F<"help">, HelpText<"Print option help">;
+
+def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
+
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">;
+
+def image_base : J<"image-base=">, HelpText<"Set the base address">;
+
+def init: S<"init">, MetaVarName<"<symbol>">,
+  HelpText<"Specify an initializer function">;
+
+def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
+  HelpText<"Root name of library to use">;
+
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+  HelpText<"Optimization level for LTO">;
+
+def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+
+def Map: JS<"Map">, HelpText<"Print a link map to the specified file">;
+
+def nostdlib: F<"nostdlib">,
+  HelpText<"Only search directories specified on the command line">;
+
+def no_as_needed: F<"no-as-needed">,
+  HelpText<"Always DT_NEEDED for shared libraries">;
+
+def no_color_diagnostics: F<"no-color-diagnostics">,
+  HelpText<"Do not use colors in diagnostics">;
+
+def no_define_common: F<"no-define-common">,
+  HelpText<"Do not assign space to common symbols">;
+
+def no_demangle: F<"no-demangle">,
+  HelpText<"Do not demangle symbol names">;
+
+def no_dynamic_linker: F<"no-dynamic-linker">,
+  HelpText<"Inhibit output of .interp section">;
+
+def no_export_dynamic: F<"no-export-dynamic">;
+def no_fatal_warnings: F<"no-fatal-warnings">;
+
+def no_gc_sections: F<"no-gc-sections">,
+  HelpText<"Disable garbage collection of unused sections">;
+
+def no_gnu_unique: F<"no-gnu-unique">,
+  HelpText<"Disable STB_GNU_UNIQUE symbol binding">;
+
+def no_threads: F<"no-threads">,
+  HelpText<"Do not run the linker multi-threaded">;
+
+def no_whole_archive: F<"no-whole-archive">,
+  HelpText<"Restores the default behavior of loading archive members">;
+
+def noinhibit_exec: F<"noinhibit-exec">,
+  HelpText<"Retain the executable output file whenever it is still usable">;
+
+def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">;
+
+def no_rosegment: F<"no-rosegment">, HelpText<"Do not put read-only non-executable sections in their own segment">;
+
+def no_undefined: F<"no-undefined">,
+  HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
+
+def no_undefined_version: F<"no-undefined-version">,
+  HelpText<"Report version scripts that refer undefined symbols">;
+
+def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
+  HelpText<"Path to file to write output">;
+
+def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
+  HelpText<"Specify the binary format for the output object file">;
+
+def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
+  HelpText<"Set the text and data sections to be readable and writable">;
+
+def pie: F<"pie">, HelpText<"Create a position independent executable">;
+
+def print_gc_sections: F<"print-gc-sections">,
+  HelpText<"List removed unused sections">;
+
+def print_map: F<"print-map">,
+  HelpText<"Print a link map to the standard output">;
+
+def reproduce: S<"reproduce">,
+  HelpText<"Dump linker invocation and input files for debugging">;
+
+def rpath: S<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
+
+def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
+
+def retain_symbols_file: J<"retain-symbols-file=">, MetaVarName<"<file>">,
+  HelpText<"Retain only the symbols listed in the file">;
+
+def script: S<"script">, HelpText<"Read linker script">;
+
+def section_start: S<"section-start">, MetaVarName<"<address>">,
+  HelpText<"Set address of section">;
+
+def shared: F<"shared">, HelpText<"Build a shared object">;
+
+def soname: J<"soname=">, HelpText<"Set DT_SONAME">;
+
+def sort_section: S<"sort-section">, HelpText<"Specifies sections sorting rule when linkerscript is used">;
+
+def start_lib: F<"start-lib">,
+  HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
+
+def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
+
+def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
+
+def symbol_ordering_file: S<"symbol-ordering-file">,
+  HelpText<"Layout sections in the order specified by symbol file">;
+
+def sysroot: J<"sysroot=">, HelpText<"Set the system root">;
+
+def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
+
+def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
+
+def target2: J<"target2=">, MetaVarName<"<type>">, HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">;
+
+def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+
+def trace: F<"trace">, HelpText<"Print the names of the input files">;
+
+def trace_symbol : S<"trace-symbol">, HelpText<"Trace references to symbols">;
+
+def undefined: S<"undefined">,
+  HelpText<"Force undefined symbol during linking">;
+
+def unresolved_symbols: J<"unresolved-symbols=">,
+  HelpText<"Determine how to handle unresolved symbols">;
+
+def rsp_quoting: J<"rsp-quoting=">,
+  HelpText<"Quoting style for response files. Values supported: windows|posix">;
+
+def v: Flag<["-"], "v">, HelpText<"Display the version number">;
+
+def verbose: F<"verbose">, HelpText<"Verbose mode">;
+
+def version: F<"version">, HelpText<"Display the version number and exit">;
+
+def version_script: S<"version-script">,
+  HelpText<"Read a version script">;
+
+def warn_common: F<"warn-common">,
+  HelpText<"Warn about duplicate common symbols">;
+
+def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
+  HelpText<"Report unresolved symbols as warnings">;
+
+def whole_archive: F<"whole-archive">,
+  HelpText<"Force load of all members in a static library">;
+
+def wrap: S<"wrap">, MetaVarName<"<symbol>">,
+  HelpText<"Use wrapper functions for symbol">;
+
+def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
+  HelpText<"Linker option extensions">;
+
+// Aliases
+def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>;
+def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>;
+def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>;
+def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>;
+def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
+def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
+def alias_L__library_path: J<"library-path=">, Alias<L>;
+def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>;
+def alias_define_common_dc: F<"dc">, Alias<define_common>;
+def alias_define_common_dp: F<"dp">, Alias<define_common>;
+def alias_defsym: S<"defsym">, Alias<defsym>;
+def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
+def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
+def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
+def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
+def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
+def alias_entry_entry: J<"entry=">, Alias<entry>;
+def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
+def alias_exclude_libs: J<"exclude-libs=">, Alias<exclude_libs>;
+def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
+def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
+  Alias<export_dynamic_symbol>;
+def alias_filter: Separate<["-"], "F">, Alias<filter>;
+def alias_fini_fini: J<"fini=">, Alias<fini>;
+def alias_format_b: S<"b">, Alias<format>;
+def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
+def alias_init_init: J<"init=">, Alias<init>;
+def alias_l__library: J<"library=">, Alias<l>;
+def alias_Map_eq: J<"Map=">, Alias<Map>;
+def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
+def alias_o_output: Joined<["--"], "output=">, Alias<o>;
+def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
+def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
+def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
+def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
+def alias_reproduce_eq: J<"reproduce=">, Alias<reproduce>;
+def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;
+def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
+def alias_rpath_rpath: J<"rpath=">, Alias<rpath>;
+def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>;
+def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>;
+def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>;
+def alias_soname_soname: S<"soname">, Alias<soname>;
+def alias_sort_section: J<"sort-section=">, Alias<sort_section>;
+def alias_script: J<"script=">, Alias<script>;
+def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
+def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
+def alias_Tbss: J<"Tbss=">, Alias<Tbss>;
+def alias_Tdata: J<"Tdata=">, Alias<Tdata>;
+def alias_trace: Flag<["-"], "t">, Alias<trace>;
+def trace_trace_symbol_eq : J<"trace-symbol=">, Alias<trace_symbol>;
+def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
+def alias_Ttext: J<"Ttext=">, Alias<Ttext>;
+def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
+def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>;
+def alias_undefined_eq: J<"undefined=">, Alias<undefined>;
+def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+def alias_version_script_eq: J<"version-script=">, Alias<version_script>;
+def alias_version_V: Flag<["-"], "V">, Alias<version>;
+def alias_wrap_wrap: J<"wrap=">, Alias<wrap>;
+
+// Our symbol resolution algorithm handles symbols in archive files differently
+// than traditional linkers, so we don't need --start-group and --end-group.
+// These options are recongized for compatibility but ignored.
+def end_group: F<"end-group">;
+def end_group_paren: Flag<["-"], ")">;
+def start_group: F<"start-group">;
+def start_group_paren: Flag<["-"], "(">;
+
+// LTO-related options.
+def lto_aa_pipeline: J<"lto-aa-pipeline=">,
+  HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_newpm_passes: J<"lto-newpm-passes=">,
+  HelpText<"Passes to run during LTO">;
+def lto_partitions: J<"lto-partitions=">,
+  HelpText<"Number of LTO codegen partitions">;
+def disable_verify: F<"disable-verify">;
+def mllvm: S<"mllvm">;
+def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
+  HelpText<"YAML output file for optimization remarks">;
+def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
+  HelpText<"Include hotness informations in the optimization remarks file">;
+def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+  HelpText<"Path to ThinLTO cached object file directory">;
+def thinlto_cache_policy: S<"thinlto-cache-policy">,
+  HelpText<"Pruning policy for the ThinLTO cache">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+
+// Ignore LTO plugin-related options.
+// clang -flto passes -plugin and -plugin-opt to the linker. This is required
+// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
+// rely on a plugin. Instead of detecting which linker is used on clang side we
+// just ignore the option on lld side as it's easier. In fact, the linker could
+// be called 'ld' and understanding which linker is used would require parsing of
+// --version output.
+def plugin: S<"plugin">;
+def plugin_eq: J<"plugin=">;
+def plugin_opt: S<"plugin-opt">;
+def plugin_opt_eq: J<"plugin-opt=">;
+
+// Options listed below are silently ignored for now for compatibility.
+def allow_shlib_undefined: F<"allow-shlib-undefined">;
+def cref: Flag<["--"], "cref">;
+def detect_odr_violations: F<"detect-odr-violations">;
+def g: Flag<["-"], "g">;
+def no_add_needed: F<"no-add-needed">;
+def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
+def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
+  Alias<no_add_needed>;
+def no_keep_memory: F<"no-keep-memory">;
+def no_mmap_output_file: F<"no-mmap-output-file">;
+def no_warn_common: F<"no-warn-common">;
+def no_warn_mismatch: F<"no-warn-mismatch">;
+def rpath_link: S<"rpath-link">;
+def rpath_link_eq: J<"rpath-link=">;
+def sort_common: F<"sort-common">;
+def stats: F<"stats">;
+def warn_execstack: F<"warn-execstack">;
+def warn_shared_textrel: F<"warn-shared-textrel">;
+def EB : F<"EB">;
+def EL : F<"EL">;
+def G: JoinedOrSeparate<["-"], "G">;
+def Qy : F<"Qy">;
+
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
new file mode 100644 (file)
index 0000000..abe5481
--- /dev/null
@@ -0,0 +1,277 @@
+//===- OutputSections.cpp -------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OutputSections.h"
+#include "Config.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Threads.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SHA1.h"
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+uint8_t Out::First;
+OutputSection *Out::Opd;
+uint8_t *Out::OpdBuf;
+PhdrEntry *Out::TlsPhdr;
+OutputSection *Out::DebugInfo;
+OutputSection *Out::ElfHeader;
+OutputSection *Out::ProgramHeaders;
+OutputSection *Out::PreinitArray;
+OutputSection *Out::InitArray;
+OutputSection *Out::FiniArray;
+
+std::vector<OutputSection *> elf::OutputSections;
+std::vector<OutputSectionCommand *> elf::OutputSectionCommands;
+
+uint32_t OutputSection::getPhdrFlags() const {
+  uint32_t Ret = PF_R;
+  if (Flags & SHF_WRITE)
+    Ret |= PF_W;
+  if (Flags & SHF_EXECINSTR)
+    Ret |= PF_X;
+  return Ret;
+}
+
+template <class ELFT>
+void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
+  Shdr->sh_entsize = Entsize;
+  Shdr->sh_addralign = Alignment;
+  Shdr->sh_type = Type;
+  Shdr->sh_offset = Offset;
+  Shdr->sh_flags = Flags;
+  Shdr->sh_info = Info;
+  Shdr->sh_link = Link;
+  Shdr->sh_addr = Addr;
+  Shdr->sh_size = Size;
+  Shdr->sh_name = ShName;
+}
+
+OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
+    : SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
+                  /*Info*/ 0,
+                  /*Link*/ 0),
+      SectionIndex(INT_MAX) {}
+
+static uint64_t updateOffset(uint64_t Off, InputSection *S) {
+  Off = alignTo(Off, S->Alignment);
+  S->OutSecOff = Off;
+  return Off + S->getSize();
+}
+
+void OutputSection::addSection(InputSection *S) {
+  assert(S->Live);
+  Sections.push_back(S);
+  S->Parent = this;
+  this->updateAlignment(S->Alignment);
+
+  // The actual offsets will be computed by assignAddresses. For now, use
+  // crude approximation so that it is at least easy for other code to know the
+  // section order. It is also used to calculate the output section size early
+  // for compressed debug sections.
+  this->Size = updateOffset(Size, S);
+
+  // If this section contains a table of fixed-size entries, sh_entsize
+  // holds the element size. Consequently, if this contains two or more
+  // input sections, all of them must have the same sh_entsize. However,
+  // you can put different types of input sections into one output
+  // sectin by using linker scripts. I don't know what to do here.
+  // Probably we sholuld handle that as an error. But for now we just
+  // pick the largest sh_entsize.
+  this->Entsize = std::max(this->Entsize, S->Entsize);
+}
+
+static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
+  //  The ELF spec just says
+  // ----------------------------------------------------------------
+  // In the first phase, input sections that match in name, type and
+  // attribute flags should be concatenated into single sections.
+  // ----------------------------------------------------------------
+  //
+  // However, it is clear that at least some flags have to be ignored for
+  // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be
+  // ignored. We should not have two output .text sections just because one was
+  // in a group and another was not for example.
+  //
+  // It also seems that that wording was a late addition and didn't get the
+  // necessary scrutiny.
+  //
+  // Merging sections with different flags is expected by some users. One
+  // reason is that if one file has
+  //
+  // int *const bar __attribute__((section(".foo"))) = (int *)0;
+  //
+  // gcc with -fPIC will produce a read only .foo section. But if another
+  // file has
+  //
+  // int zed;
+  // int *const bar __attribute__((section(".foo"))) = (int *)&zed;
+  //
+  // gcc with -fPIC will produce a read write section.
+  //
+  // Last but not least, when using linker script the merge rules are forced by
+  // the script. Unfortunately, linker scripts are name based. This means that
+  // expressions like *(.foo*) can refer to multiple input sections with
+  // different flags. We cannot put them in different output sections or we
+  // would produce wrong results for
+  //
+  // start = .; *(.foo.*) end = .; *(.bar)
+  //
+  // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to
+  // another. The problem is that there is no way to layout those output
+  // sections such that the .foo sections are the only thing between the start
+  // and end symbols.
+  //
+  // Given the above issues, we instead merge sections by name and error on
+  // incompatible types and flags.
+
+  uint32_t Alignment = 0;
+  uint64_t Flags = 0;
+  if (Config->Relocatable && (C->Flags & SHF_MERGE)) {
+    Alignment = std::max<uint64_t>(C->Alignment, C->Entsize);
+    Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
+  }
+
+  return SectionKey{OutsecName, Flags, Alignment};
+}
+
+OutputSectionFactory::OutputSectionFactory() {}
+
+static uint64_t getIncompatibleFlags(uint64_t Flags) {
+  return Flags & (SHF_ALLOC | SHF_TLS);
+}
+
+// We allow sections of types listed below to merged into a
+// single progbits section. This is typically done by linker
+// scripts. Merging nobits and progbits will force disk space
+// to be allocated for nobits sections. Other ones don't require
+// any special treatment on top of progbits, so there doesn't
+// seem to be a harm in merging them.
+static bool canMergeToProgbits(unsigned Type) {
+  return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY ||
+         Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY ||
+         Type == SHT_NOTE;
+}
+
+void elf::reportDiscarded(InputSectionBase *IS) {
+  if (!Config->PrintGcSections)
+    return;
+  message("removing unused section from '" + IS->Name + "' in file '" +
+          IS->File->getName() + "'");
+}
+
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+                                       StringRef OutsecName) {
+  // Sections with the SHT_GROUP attribute reach here only when the - r option
+  // is given. Such sections define "section groups", and InputFiles.cpp has
+  // dedup'ed section groups by their signatures. For the -r, we want to pass
+  // through all SHT_GROUP sections without merging them because merging them
+  // creates broken section contents.
+  if (IS->Type == SHT_GROUP) {
+    OutputSection *Out = nullptr;
+    addInputSec(IS, OutsecName, Out);
+    return;
+  }
+
+  // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have
+  // relocation sections .rela.foo and .rela.bar for example. Most tools do
+  // not allow multiple REL[A] sections for output section. Hence we
+  // should combine these relocation sections into single output.
+  // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any
+  // other REL[A] sections created by linker itself.
+  if (!isa<SyntheticSection>(IS) &&
+      (IS->Type == SHT_REL || IS->Type == SHT_RELA)) {
+    auto *Sec = cast<InputSection>(IS);
+    OutputSection *Out = Sec->getRelocatedSection()->getOutputSection();
+    addInputSec(IS, OutsecName, Out->RelocationSection);
+    return;
+  }
+
+  SectionKey Key = createKey(IS, OutsecName);
+  OutputSection *&Sec = Map[Key];
+  addInputSec(IS, OutsecName, Sec);
+}
+
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+                                       StringRef OutsecName,
+                                       OutputSection *&Sec) {
+  if (!IS->Live) {
+    reportDiscarded(IS);
+    return;
+  }
+
+  if (Sec) {
+    if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
+      error("incompatible section flags for " + Sec->Name + "\n>>> " +
+            toString(IS) + ": 0x" + utohexstr(IS->Flags) +
+            "\n>>> output section " + Sec->Name + ": 0x" +
+            utohexstr(Sec->Flags));
+    if (Sec->Type != IS->Type) {
+      if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type))
+        Sec->Type = SHT_PROGBITS;
+      else
+        error("section type mismatch for " + IS->Name + "\n>>> " +
+              toString(IS) + ": " +
+              getELFSectionTypeName(Config->EMachine, IS->Type) +
+              "\n>>> output section " + Sec->Name + ": " +
+              getELFSectionTypeName(Config->EMachine, Sec->Type));
+    }
+    Sec->Flags |= IS->Flags;
+  } else {
+    Sec = make<OutputSection>(OutsecName, IS->Type, IS->Flags);
+    OutputSections.push_back(Sec);
+  }
+
+  Sec->addSection(cast<InputSection>(IS));
+}
+
+OutputSectionFactory::~OutputSectionFactory() {}
+
+SectionKey DenseMapInfo<SectionKey>::getEmptyKey() {
+  return SectionKey{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
+}
+
+SectionKey DenseMapInfo<SectionKey>::getTombstoneKey() {
+  return SectionKey{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0};
+}
+
+unsigned DenseMapInfo<SectionKey>::getHashValue(const SectionKey &Val) {
+  return hash_combine(Val.Name, Val.Flags, Val.Alignment);
+}
+
+bool DenseMapInfo<SectionKey>::isEqual(const SectionKey &LHS,
+                                       const SectionKey &RHS) {
+  return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
+         LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment;
+}
+
+uint64_t elf::getHeaderSize() {
+  if (Config->OFormatBinary)
+    return 0;
+  return Out::ElfHeader->Size + Out::ProgramHeaders->Size;
+}
+
+template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
new file mode 100644 (file)
index 0000000..68b46eb
--- /dev/null
@@ -0,0 +1,153 @@
+//===- OutputSections.h -----------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_OUTPUT_SECTIONS_H
+#define LLD_ELF_OUTPUT_SECTIONS_H
+
+#include "Config.h"
+#include "InputSection.h"
+#include "Relocations.h"
+
+#include "lld/Core/LLVM.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+
+struct PhdrEntry;
+class SymbolBody;
+struct EhSectionPiece;
+class EhInputSection;
+class InputSection;
+class InputSectionBase;
+class MergeInputSection;
+class OutputSection;
+template <class ELFT> class ObjectFile;
+template <class ELFT> class SharedFile;
+class SharedSymbol;
+class DefinedRegular;
+
+// This represents a section in an output file.
+// It is composed of multiple InputSections.
+// The writer creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and VAs.
+class OutputSection final : public SectionBase {
+public:
+  OutputSection(StringRef Name, uint32_t Type, uint64_t Flags);
+
+  static bool classof(const SectionBase *S) {
+    return S->kind() == SectionBase::Output;
+  }
+
+  uint64_t getLMA() const { return Addr + LMAOffset; }
+  template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
+
+  unsigned SectionIndex;
+  unsigned SortRank;
+
+  uint32_t getPhdrFlags() const;
+
+  void updateAlignment(uint32_t Val) {
+    if (Val > Alignment)
+      Alignment = Val;
+  }
+
+  // Pointer to the first section in PT_LOAD segment, which this section
+  // also resides in. This field is used to correctly compute file offset
+  // of a section. When two sections share the same load segment, difference
+  // between their file offsets should be equal to difference between their
+  // virtual addresses. To compute some section offset we use the following
+  // formula: Off = Off_first + VA - VA_first.
+  OutputSection *FirstInPtLoad = nullptr;
+
+  // Pointer to a relocation section for this section. Usually nullptr because
+  // we consume relocations, but if --emit-relocs is specified (which is rare),
+  // it may have a non-null value.
+  OutputSection *RelocationSection = nullptr;
+
+  // The following fields correspond to Elf_Shdr members.
+  uint64_t Size = 0;
+  uint64_t Offset = 0;
+  uint64_t LMAOffset = 0;
+  uint64_t Addr = 0;
+  uint32_t ShName = 0;
+
+  void addSection(InputSection *S);
+  std::vector<InputSection *> Sections;
+
+  // Used for implementation of --compress-debug-sections option.
+  std::vector<uint8_t> ZDebugHeader;
+  llvm::SmallVector<char, 1> CompressedData;
+
+  // Location in the output buffer.
+  uint8_t *Loc = nullptr;
+};
+
+// All output sections that are handled by the linker specially are
+// globally accessible. Writer initializes them, so don't use them
+// until Writer is initialized.
+struct Out {
+  static uint8_t First;
+  static OutputSection *Opd;
+  static uint8_t *OpdBuf;
+  static PhdrEntry *TlsPhdr;
+  static OutputSection *DebugInfo;
+  static OutputSection *ElfHeader;
+  static OutputSection *ProgramHeaders;
+  static OutputSection *PreinitArray;
+  static OutputSection *InitArray;
+  static OutputSection *FiniArray;
+};
+
+struct SectionKey {
+  StringRef Name;
+  uint64_t Flags;
+  uint32_t Alignment;
+};
+} // namespace elf
+} // namespace lld
+namespace llvm {
+template <> struct DenseMapInfo<lld::elf::SectionKey> {
+  static lld::elf::SectionKey getEmptyKey();
+  static lld::elf::SectionKey getTombstoneKey();
+  static unsigned getHashValue(const lld::elf::SectionKey &Val);
+  static bool isEqual(const lld::elf::SectionKey &LHS,
+                      const lld::elf::SectionKey &RHS);
+};
+} // namespace llvm
+namespace lld {
+namespace elf {
+
+// This class knows how to create an output section for a given
+// input section. Output section type is determined by various
+// factors, including input section's sh_flags, sh_type and
+// linker scripts.
+class OutputSectionFactory {
+public:
+  OutputSectionFactory();
+  ~OutputSectionFactory();
+
+  void addInputSec(InputSectionBase *IS, StringRef OutsecName);
+  void addInputSec(InputSectionBase *IS, StringRef OutsecName,
+                   OutputSection *&Sec);
+
+private:
+  llvm::SmallDenseMap<SectionKey, OutputSection *> Map;
+};
+
+uint64_t getHeaderSize();
+void reportDiscarded(InputSectionBase *IS);
+
+extern std::vector<OutputSection *> OutputSections;
+extern std::vector<OutputSectionCommand *> OutputSectionCommands;
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/README.md b/ELF/README.md
new file mode 100644 (file)
index 0000000..f1bfc9c
--- /dev/null
@@ -0,0 +1 @@
+See docs/NewLLD.rst
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
new file mode 100644 (file)
index 0000000..e5fcb2d
--- /dev/null
@@ -0,0 +1,1144 @@
+//===- Relocations.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains platform-independent functions to process relocations.
+// I'll describe the overview of this file here.
+//
+// Simple relocations are easy to handle for the linker. For example,
+// for R_X86_64_PC64 relocs, the linker just has to fix up locations
+// with the relative offsets to the target symbols. It would just be
+// reading records from relocation sections and applying them to output.
+//
+// But not all relocations are that easy to handle. For example, for
+// R_386_GOTOFF relocs, the linker has to create new GOT entries for
+// symbols if they don't exist, and fix up locations with GOT entry
+// offsets from the beginning of GOT section. So there is more than
+// fixing addresses in relocation processing.
+//
+// ELF defines a large number of complex relocations.
+//
+// The functions in this file analyze relocations and do whatever needs
+// to be done. It includes, but not limited to, the following.
+//
+//  - create GOT/PLT entries
+//  - create new relocations in .dynsym to let the dynamic linker resolve
+//    them at runtime (since ELF supports dynamic linking, not all
+//    relocations can be resolved at link-time)
+//  - create COPY relocs and reserve space in .bss
+//  - replace expensive relocs (in terms of runtime cost) with cheap ones
+//  - error out infeasible combinations such as PIC and non-relative relocs
+//
+// Note that the functions in this file don't actually apply relocations
+// because it doesn't know about the output file nor the output file buffer.
+// It instead stores Relocation objects to InputSection's Relocations
+// vector to let it apply later in InputSection::writeTo.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Relocations.h"
+#include "Config.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Construct a message in the following format.
+//
+// >>> defined in /home/alice/src/foo.o
+// >>> referenced by bar.c:12 (/home/alice/src/bar.c:12)
+// >>>               /home/alice/src/bar.o:(.text+0x1)
+template <class ELFT>
+static std::string getLocation(InputSectionBase &S, const SymbolBody &Sym,
+                               uint64_t Off) {
+  std::string Msg =
+      "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by ";
+  std::string Src = S.getSrcMsg<ELFT>(Off);
+  if (!Src.empty())
+    Msg += Src + "\n>>>               ";
+  return Msg + S.getObjMsg<ELFT>(Off);
+}
+
+static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
+  // In case of MIPS GP-relative relocations always resolve to a definition
+  // in a regular input file, ignoring the one-definition rule. So we,
+  // for example, should not attempt to create a dynamic relocation even
+  // if the target symbol is preemptible. There are two two MIPS GP-relative
+  // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
+  // can be against a preemptible symbol.
+  // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all
+  // relocation types occupy eight bit. In case of N64 ABI we extract first
+  // relocation from 3-in-1 packet because only the first relocation can
+  // be against a real symbol.
+  if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
+    return false;
+  return Body.isPreemptible();
+}
+
+// This function is similar to the `handleTlsRelocation`. MIPS does not
+// support any relaxations for TLS relocations so by factoring out MIPS
+// handling in to the separate function we can simplify the code and do not
+// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
+// Mips has a custom MipsGotSection that handles the writing of GOT entries
+// without dynamic relocations.
+template <class ELFT>
+static unsigned handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
+                                        InputSectionBase &C, uint64_t Offset,
+                                        int64_t Addend, RelExpr Expr) {
+  if (Expr == R_MIPS_TLSLD) {
+    if (InX::MipsGot->addTlsIndex() && Config->Pic)
+      In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot,
+                                   InX::MipsGot->getTlsIndexOff(), false,
+                                   nullptr, 0});
+    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+    return 1;
+  }
+
+  if (Expr == R_MIPS_TLSGD) {
+    if (InX::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) {
+      uint64_t Off = InX::MipsGot->getGlobalDynOffset(Body);
+      In<ELFT>::RelaDyn->addReloc(
+          {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Body, 0});
+      if (Body.isPreemptible())
+        In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot,
+                                     Off + Config->Wordsize, false, &Body, 0});
+    }
+    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+    return 1;
+  }
+  return 0;
+}
+
+// This function is similar to the `handleMipsTlsRelocation`. ARM also does not
+// support any relaxations for TLS relocations. ARM is logically similar to Mips
+// in how it handles TLS, but Mips uses its own custom GOT which handles some
+// of the cases that ARM uses GOT relocations for.
+//
+// We look for TLS global dynamic and local dynamic relocations, these may
+// require the generation of a pair of GOT entries that have associated
+// dynamic relocations. When the results of the dynamic relocations can be
+// resolved at static link time we do so. This is necessary for static linking
+// as there will be no dynamic loader to resolve them at load-time.
+//
+// The pair of GOT entries created are of the form
+// GOT[e0] Module Index (Used to find pointer to TLS block at run-time)
+// GOT[e1] Offset of symbol in TLS block
+template <class ELFT>
+static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body,
+                                       InputSectionBase &C, uint64_t Offset,
+                                       int64_t Addend, RelExpr Expr) {
+  // The Dynamic TLS Module Index Relocation for a symbol defined in an
+  // executable is always 1. If the target Symbol is not preemtible then
+  // we know the offset into the TLS block at static link time.
+  bool NeedDynId = Body.isPreemptible() || Config->Shared;
+  bool NeedDynOff = Body.isPreemptible();
+
+  auto AddTlsReloc = [&](uint64_t Off, uint32_t Type, SymbolBody *Dest,
+                         bool Dyn) {
+    if (Dyn)
+      In<ELFT>::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0});
+    else
+      InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
+  };
+
+  // Local Dynamic is for access to module local TLS variables, while still
+  // being suitable for being dynamically loaded via dlopen.
+  // GOT[e0] is the module index, with a special value of 0 for the current
+  // module. GOT[e1] is unused. There only needs to be one module index entry.
+  if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) {
+    AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
+                NeedDynId ? nullptr : &Body, NeedDynId);
+    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+    return 1;
+  }
+
+  // Global Dynamic is the most general purpose access model. When we know
+  // the module index and offset of symbol in TLS block we can fill these in
+  // using static GOT relocations.
+  if (Expr == R_TLSGD_PC) {
+    if (InX::Got->addDynTlsEntry(Body)) {
+      uint64_t Off = InX::Got->getGlobalDynOffset(Body);
+      AddTlsReloc(Off, Target->TlsModuleIndexRel, &Body, NeedDynId);
+      AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Body,
+                  NeedDynOff);
+    }
+    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+    return 1;
+  }
+  return 0;
+}
+
+// Returns the number of relocations processed.
+template <class ELFT>
+static unsigned
+handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
+                    typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
+  if (!(C.Flags & SHF_ALLOC))
+    return 0;
+
+  if (!Body.isTls())
+    return 0;
+
+  if (Config->EMachine == EM_ARM)
+    return handleARMTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+  if (Config->EMachine == EM_MIPS)
+    return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+
+  bool IsPreemptible = isPreemptible(Body, Type);
+  if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
+      Config->Shared) {
+    if (InX::Got->addDynTlsEntry(Body)) {
+      uint64_t Off = InX::Got->getGlobalDynOffset(Body);
+      In<ELFT>::RelaDyn->addReloc(
+          {Target->TlsDescRel, InX::Got, Off, !IsPreemptible, &Body, 0});
+    }
+    if (Expr != R_TLSDESC_CALL)
+      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+    return 1;
+  }
+
+  if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
+    // Local-Dynamic relocs can be relaxed to Local-Exec.
+    if (!Config->Shared) {
+      C.Relocations.push_back(
+          {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
+      return 2;
+    }
+    if (InX::Got->addTlsIndex())
+      In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got,
+                                   InX::Got->getTlsIndexOff(), false, nullptr,
+                                   0});
+    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+    return 1;
+  }
+
+  // Local-Dynamic relocs can be relaxed to Local-Exec.
+  if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) {
+    C.Relocations.push_back(
+        {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
+    return 1;
+  }
+
+  if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
+                     R_TLSGD_PC>(Expr)) {
+    if (Config->Shared) {
+      if (InX::Got->addDynTlsEntry(Body)) {
+        uint64_t Off = InX::Got->getGlobalDynOffset(Body);
+        In<ELFT>::RelaDyn->addReloc(
+            {Target->TlsModuleIndexRel, InX::Got, Off, false, &Body, 0});
+
+        // If the symbol is preemptible we need the dynamic linker to write
+        // the offset too.
+        uint64_t OffsetOff = Off + Config->Wordsize;
+        if (IsPreemptible)
+          In<ELFT>::RelaDyn->addReloc(
+              {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Body, 0});
+        else
+          InX::Got->Relocations.push_back(
+              {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Body});
+      }
+      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+      return 1;
+    }
+
+    // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
+    // depending on the symbol being locally defined or not.
+    if (IsPreemptible) {
+      C.Relocations.push_back(
+          {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
+           Offset, Addend, &Body});
+      if (!Body.isInGot()) {
+        InX::Got->addEntry(Body);
+        In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::Got,
+                                     Body.getGotOffset(), false, &Body, 0});
+      }
+    } else {
+      C.Relocations.push_back(
+          {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
+           Offset, Addend, &Body});
+    }
+    return Target->TlsGdRelaxSkip;
+  }
+
+  // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
+  // defined.
+  if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC>(Expr) &&
+      !Config->Shared && !IsPreemptible) {
+    C.Relocations.push_back(
+        {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
+    return 1;
+  }
+
+  if (Expr == R_TLSDESC_CALL)
+    return 1;
+  return 0;
+}
+
+static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) {
+  switch (Type) {
+  case R_MIPS_HI16:
+    return R_MIPS_LO16;
+  case R_MIPS_GOT16:
+    return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
+  case R_MIPS_PCHI16:
+    return R_MIPS_PCLO16;
+  case R_MICROMIPS_HI16:
+    return R_MICROMIPS_LO16;
+  default:
+    return R_MIPS_NONE;
+  }
+}
+
+// True if non-preemptable symbol always has the same value regardless of where
+// the DSO is loaded.
+static bool isAbsolute(const SymbolBody &Body) {
+  if (Body.isUndefined())
+    return !Body.isLocal() && Body.symbol()->isWeak();
+  if (const auto *DR = dyn_cast<DefinedRegular>(&Body))
+    return DR->Section == nullptr; // Absolute symbol.
+  return false;
+}
+
+static bool isAbsoluteValue(const SymbolBody &Body) {
+  return isAbsolute(Body) || Body.isTls();
+}
+
+// Returns true if Expr refers a PLT entry.
+static bool needsPlt(RelExpr Expr) {
+  return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+}
+
+// Returns true if Expr refers a GOT entry. Note that this function
+// returns false for TLS variables even though they need GOT, because
+// TLS variables uses GOT differently than the regular variables.
+static bool needsGot(RelExpr Expr) {
+  return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
+                        R_MIPS_GOT_OFF32, R_GOT_PAGE_PC, R_GOT_PC,
+                        R_GOT_FROM_END>(Expr);
+}
+
+// True if this expression is of the form Sym - X, where X is a position in the
+// file (PC, or GOT for example).
+static bool isRelExpr(RelExpr Expr) {
+  return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
+                        R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+}
+
+// Returns true if a given relocation can be computed at link-time.
+//
+// For instance, we know the offset from a relocation to its target at
+// link-time if the relocation is PC-relative and refers a
+// non-interposable function in the same executable. This function
+// will return true for such relocation.
+//
+// If this function returns false, that means we need to emit a
+// dynamic relocation so that the relocation will be fixed at load-time.
+template <class ELFT>
+static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
+                                     const SymbolBody &Body,
+                                     InputSectionBase &S, uint64_t RelOff) {
+  // These expressions always compute a constant
+  if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+                     R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
+                     R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+                     R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
+                     R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
+    return true;
+
+  // These never do, except if the entire file is position dependent or if
+  // only the low bits are used.
+  if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
+    return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
+
+  if (isPreemptible(Body, Type))
+    return false;
+  if (!Config->Pic)
+    return true;
+
+  // For the target and the relocation, we want to know if they are
+  // absolute or relative.
+  bool AbsVal = isAbsoluteValue(Body);
+  bool RelE = isRelExpr(E);
+  if (AbsVal && !RelE)
+    return true;
+  if (!AbsVal && RelE)
+    return true;
+  if (!AbsVal && !RelE)
+    return Target->usesOnlyLowPageBits(Type);
+
+  // Relative relocation to an absolute value. This is normally unrepresentable,
+  // but if the relocation refers to a weak undefined symbol, we allow it to
+  // resolve to the image base. This is a little strange, but it allows us to
+  // link function calls to such symbols. Normally such a call will be guarded
+  // with a comparison, which will load a zero from the GOT.
+  // Another special case is MIPS _gp_disp symbol which represents offset
+  // between start of a function and '_gp' value and defined as absolute just
+  // to simplify the code.
+  assert(AbsVal && RelE);
+  if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+    return true;
+
+  error("relocation " + toString(Type) + " cannot refer to absolute symbol: " +
+        toString(Body) + getLocation<ELFT>(S, Body, RelOff));
+  return true;
+}
+
+static RelExpr toPlt(RelExpr Expr) {
+  if (Expr == R_PPC_OPD)
+    return R_PPC_PLT_OPD;
+  if (Expr == R_PC)
+    return R_PLT_PC;
+  if (Expr == R_PAGE_PC)
+    return R_PLT_PAGE_PC;
+  if (Expr == R_ABS)
+    return R_PLT;
+  return Expr;
+}
+
+static RelExpr fromPlt(RelExpr Expr) {
+  // We decided not to use a plt. Optimize a reference to the plt to a
+  // reference to the symbol itself.
+  if (Expr == R_PLT_PC)
+    return R_PC;
+  if (Expr == R_PPC_PLT_OPD)
+    return R_PPC_OPD;
+  if (Expr == R_PLT)
+    return R_ABS;
+  return Expr;
+}
+
+// Returns true if a given shared symbol is in a read-only segment in a DSO.
+template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
+  typedef typename ELFT::Phdr Elf_Phdr;
+  uint64_t Value = SS->getValue<ELFT>();
+
+  // Determine if the symbol is read-only by scanning the DSO's program headers.
+  auto *File = cast<SharedFile<ELFT>>(SS->File);
+  for (const Elf_Phdr &Phdr : check(File->getObj().program_headers()))
+    if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
+        !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr &&
+        Value < Phdr.p_vaddr + Phdr.p_memsz)
+      return true;
+  return false;
+}
+
+// Returns symbols at the same offset as a given symbol, including SS itself.
+//
+// If two or more symbols are at the same offset, and at least one of
+// them are copied by a copy relocation, all of them need to be copied.
+// Otherwise, they would refer different places at runtime.
+template <class ELFT>
+static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
+  typedef typename ELFT::Sym Elf_Sym;
+
+  auto *File = cast<SharedFile<ELFT>>(SS->File);
+  uint64_t Shndx = SS->getShndx<ELFT>();
+  uint64_t Value = SS->getValue<ELFT>();
+
+  std::vector<SharedSymbol *> Ret;
+  for (const Elf_Sym &S : File->getGlobalSymbols()) {
+    if (S.st_shndx != Shndx || S.st_value != Value)
+      continue;
+    StringRef Name = check(S.getName(File->getStringTable()));
+    SymbolBody *Sym = Symtab<ELFT>::X->find(Name);
+    if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym))
+      Ret.push_back(Alias);
+  }
+  return Ret;
+}
+
+// Reserve space in .bss or .bss.rel.ro for copy relocation.
+//
+// The copy relocation is pretty much a hack. If you use a copy relocation
+// in your program, not only the symbol name but the symbol's size, RW/RO
+// bit and alignment become part of the ABI. In addition to that, if the
+// symbol has aliases, the aliases become part of the ABI. That's subtle,
+// but if you violate that implicit ABI, that can cause very counter-
+// intuitive consequences.
+//
+// So, what is the copy relocation? It's for linking non-position
+// independent code to DSOs. In an ideal world, all references to data
+// exported by DSOs should go indirectly through GOT. But if object files
+// are compiled as non-PIC, all data references are direct. There is no
+// way for the linker to transform the code to use GOT, as machine
+// instructions are already set in stone in object files. This is where
+// the copy relocation takes a role.
+//
+// A copy relocation instructs the dynamic linker to copy data from a DSO
+// to a specified address (which is usually in .bss) at load-time. If the
+// static linker (that's us) finds a direct data reference to a DSO
+// symbol, it creates a copy relocation, so that the symbol can be
+// resolved as if it were in .bss rather than in a DSO.
+//
+// As you can see in this function, we create a copy relocation for the
+// dynamic linker, and the relocation contains not only symbol name but
+// various other informtion about the symbol. So, such attributes become a
+// part of the ABI.
+//
+// Note for application developers: I can give you a piece of advice if
+// you are writing a shared library. You probably should export only
+// functions from your library. You shouldn't export variables.
+//
+// As an example what can happen when you export variables without knowing
+// the semantics of copy relocations, assume that you have an exported
+// variable of type T. It is an ABI-breaking change to add new members at
+// end of T even though doing that doesn't change the layout of the
+// existing members. That's because the space for the new members are not
+// reserved in .bss unless you recompile the main program. That means they
+// are likely to overlap with other data that happens to be laid out next
+// to the variable in .bss. This kind of issue is sometimes very hard to
+// debug. What's a solution? Instead of exporting a varaible V from a DSO,
+// define an accessor getV().
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
+  // Copy relocation against zero-sized symbol doesn't make sense.
+  uint64_t SymSize = SS->template getSize<ELFT>();
+  if (SymSize == 0)
+    fatal("cannot create a copy relocation for symbol " + toString(*SS));
+
+  // See if this symbol is in a read-only segment. If so, preserve the symbol's
+  // memory protection by reserving space in the .bss.rel.ro section.
+  bool IsReadOnly = isReadOnly<ELFT>(SS);
+  BssSection *Sec = IsReadOnly ? InX::BssRelRo : InX::Bss;
+  uint64_t Off = Sec->reserveSpace(SymSize, SS->getAlignment<ELFT>());
+
+  // Look through the DSO's dynamic symbol table for aliases and create a
+  // dynamic symbol for each one. This causes the copy relocation to correctly
+  // interpose any aliases.
+  for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
+    Sym->NeedsCopy = true;
+    Sym->CopyRelSec = Sec;
+    Sym->CopyRelSecOff = Off;
+    Sym->symbol()->IsUsedInRegularObj = true;
+  }
+
+  In<ELFT>::RelaDyn->addReloc({Target->CopyRel, Sec, Off, false, SS, 0});
+}
+
+template <class ELFT>
+static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type,
+                          const uint8_t *Data, InputSectionBase &S,
+                          typename ELFT::uint RelOff) {
+  if (Body.isGnuIFunc()) {
+    Expr = toPlt(Expr);
+  } else if (!isPreemptible(Body, Type)) {
+    if (needsPlt(Expr))
+      Expr = fromPlt(Expr);
+    if (Expr == R_GOT_PC && !isAbsoluteValue(Body))
+      Expr = Target->adjustRelaxExpr(Type, Data, Expr);
+  }
+
+  bool IsWrite = !Config->ZText || (S.Flags & SHF_WRITE);
+  if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
+    return Expr;
+
+  // This relocation would require the dynamic linker to write a value to read
+  // only memory. We can hack around it if we are producing an executable and
+  // the refered symbol can be preemepted to refer to the executable.
+  if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
+    error("can't create dynamic relocation " + toString(Type) + " against " +
+          (Body.getName().empty() ? "local symbol"
+                                  : "symbol: " + toString(Body)) +
+          " in readonly segment" + getLocation<ELFT>(S, Body, RelOff));
+    return Expr;
+  }
+
+  if (Body.getVisibility() != STV_DEFAULT) {
+    error("cannot preempt symbol: " + toString(Body) +
+          getLocation<ELFT>(S, Body, RelOff));
+    return Expr;
+  }
+
+  if (Body.isObject()) {
+    // Produce a copy relocation.
+    auto *B = cast<SharedSymbol>(&Body);
+    if (!B->NeedsCopy) {
+      if (Config->ZNocopyreloc)
+        error("unresolvable relocation " + toString(Type) +
+              " against symbol '" + toString(*B) +
+              "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+              getLocation<ELFT>(S, Body, RelOff));
+
+      addCopyRelSymbol<ELFT>(B);
+    }
+    return Expr;
+  }
+
+  if (Body.isFunc()) {
+    // This handles a non PIC program call to function in a shared library. In
+    // an ideal world, we could just report an error saying the relocation can
+    // overflow at runtime. In the real world with glibc, crt1.o has a
+    // R_X86_64_PC32 pointing to libc.so.
+    //
+    // The general idea on how to handle such cases is to create a PLT entry and
+    // use that as the function value.
+    //
+    // For the static linking part, we just return a plt expr and everything
+    // else will use the the PLT entry as the address.
+    //
+    // The remaining problem is making sure pointer equality still works. We
+    // need the help of the dynamic linker for that. We let it know that we have
+    // a direct reference to a so symbol by creating an undefined symbol with a
+    // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
+    // the value of the symbol we created. This is true even for got entries, so
+    // pointer equality is maintained. To avoid an infinite loop, the only entry
+    // that points to the real function is a dedicated got entry used by the
+    // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
+    // R_386_JMP_SLOT, etc).
+    Body.NeedsPltAddr = true;
+    return toPlt(Expr);
+  }
+
+  error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) +
+        " has no type");
+  return Expr;
+}
+
+// Returns an addend of a given relocation. If it is RELA, an addend
+// is in a relocation itself. If it is REL, we need to read it from an
+// input section.
+template <class ELFT, class RelTy>
+static int64_t computeAddend(const RelTy &Rel, const uint8_t *Buf) {
+  uint32_t Type = Rel.getType(Config->IsMips64EL);
+  int64_t A = RelTy::IsRela
+                  ? getAddend<ELFT>(Rel)
+                  : Target->getImplicitAddend(Buf + Rel.r_offset, Type);
+
+  if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC)
+    A += getPPC64TocBase();
+  return A;
+}
+
+// MIPS has an odd notion of "paired" relocations to calculate addends.
+// For example, if a relocation is of R_MIPS_HI16, there must be a
+// R_MIPS_LO16 relocation after that, and an addend is calculated using
+// the two relocations.
+template <class ELFT, class RelTy>
+static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec,
+                                 RelExpr Expr, SymbolBody &Body,
+                                 const RelTy *End) {
+  if (Expr == R_MIPS_GOTREL && Body.isLocal())
+    return Sec.getFile<ELFT>()->MipsGp0;
+
+  // The ABI says that the paired relocation is used only for REL.
+  // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (RelTy::IsRela)
+    return 0;
+
+  uint32_t Type = Rel.getType(Config->IsMips64EL);
+  uint32_t PairTy = getMipsPairType(Type, Body);
+  if (PairTy == R_MIPS_NONE)
+    return 0;
+
+  const uint8_t *Buf = Sec.Data.data();
+  uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
+
+  // To make things worse, paired relocations might not be contiguous in
+  // the relocation table, so we need to do linear search. *sigh*
+  for (const RelTy *RI = &Rel; RI != End; ++RI) {
+    if (RI->getType(Config->IsMips64EL) != PairTy)
+      continue;
+    if (RI->getSymbol(Config->IsMips64EL) != SymIndex)
+      continue;
+
+    endianness E = Config->Endianness;
+    int32_t Hi = (read32(Buf + Rel.r_offset, E) & 0xffff) << 16;
+    int32_t Lo = SignExtend32<16>(read32(Buf + RI->r_offset, E));
+    return Hi + Lo;
+  }
+
+  warn("can't find matching " + toString(PairTy) + " relocation for " +
+       toString(Type));
+  return 0;
+}
+
+template <class ELFT>
+static void reportUndefined(SymbolBody &Sym, InputSectionBase &S,
+                            uint64_t Offset) {
+  if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll)
+    return;
+
+  bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL &&
+                       Sym.getVisibility() == STV_DEFAULT;
+  if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
+    return;
+
+  std::string Msg =
+      "undefined symbol: " + toString(Sym) + "\n>>> referenced by ";
+
+  std::string Src = S.getSrcMsg<ELFT>(Offset);
+  if (!Src.empty())
+    Msg += Src + "\n>>>               ";
+  Msg += S.getObjMsg<ELFT>(Offset);
+
+  if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll ||
+      (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) {
+    warn(Msg);
+  } else {
+    error(Msg);
+  }
+}
+
+template <class RelTy>
+static std::pair<uint32_t, uint32_t>
+mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) {
+  // MIPS N32 ABI treats series of successive relocations with the same offset
+  // as a single relocation. The similar approach used by N64 ABI, but this ABI
+  // packs all relocations into the single relocation record. Here we emulate
+  // this for the N32 ABI. Iterate over relocation with the same offset and put
+  // theirs types into the single bit-set.
+  uint32_t Processed = 0;
+  for (; I != E && Offset == I->r_offset; ++I) {
+    ++Processed;
+    Type |= I->getType(Config->IsMips64EL) << (8 * Processed);
+  }
+  return std::make_pair(Type, Processed);
+}
+
+// .eh_frame sections are mergeable input sections, so their input
+// offsets are not linearly mapped to output section. For each input
+// offset, we need to find a section piece containing the offset and
+// add the piece's base address to the input offset to compute the
+// output offset. That isn't cheap.
+//
+// This class is to speed up the offset computation. When we process
+// relocations, we access offsets in the monotonically increasing
+// order. So we can optimize for that access pattern.
+//
+// For sections other than .eh_frame, this class doesn't do anything.
+namespace {
+class OffsetGetter {
+public:
+  explicit OffsetGetter(InputSectionBase &Sec) {
+    if (auto *Eh = dyn_cast<EhInputSection>(&Sec)) {
+      P = Eh->Pieces;
+      Size = Eh->Pieces.size();
+    }
+  }
+
+  // Translates offsets in input sections to offsets in output sections.
+  // Given offset must increase monotonically. We assume that P is
+  // sorted by InputOff.
+  uint64_t get(uint64_t Off) {
+    if (P.empty())
+      return Off;
+
+    while (I != Size && P[I].InputOff + P[I].size() <= Off)
+      ++I;
+    if (I == Size)
+      return Off;
+
+    // P must be contiguous, so there must be no holes in between.
+    assert(P[I].InputOff <= Off && "Relocation not in any piece");
+
+    // Offset -1 means that the piece is dead (i.e. garbage collected).
+    if (P[I].OutputOff == -1)
+      return -1;
+    return P[I].OutputOff + Off - P[I].InputOff;
+  }
+
+private:
+  ArrayRef<EhSectionPiece> P;
+  size_t I = 0;
+  size_t Size;
+};
+} // namespace
+
+template <class ELFT, class GotPltSection>
+static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
+                        RelocationSection<ELFT> *Rel, uint32_t Type,
+                        SymbolBody &Sym, bool UseSymVA) {
+  Plt->addEntry<ELFT>(Sym);
+  GotPlt->addEntry(Sym);
+  Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0});
+}
+
+template <class ELFT>
+static void addGotEntry(SymbolBody &Sym, bool Preemptible) {
+  InX::Got->addEntry(Sym);
+
+  uint64_t Off = Sym.getGotOffset();
+  uint32_t DynType;
+  RelExpr Expr = R_ABS;
+
+  if (Sym.isTls()) {
+    DynType = Target->TlsGotRel;
+    Expr = R_TLS;
+  } else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) {
+    DynType = Target->RelativeRel;
+  } else {
+    DynType = Target->GotRel;
+  }
+
+  bool Constant = !Preemptible && !(Config->Pic && !isAbsolute(Sym));
+  if (!Constant)
+    In<ELFT>::RelaDyn->addReloc(
+        {DynType, InX::Got, Off, !Preemptible, &Sym, 0});
+
+  if (Constant || (!Config->IsRela && !Preemptible))
+    InX::Got->Relocations.push_back({Expr, DynType, Off, 0, &Sym});
+}
+
+// The reason we have to do this early scan is as follows
+// * To mmap the output file, we need to know the size
+// * For that, we need to know how many dynamic relocs we will have.
+// It might be possible to avoid this by outputting the file with write:
+// * Write the allocated output sections, computing addresses.
+// * Apply relocations, recording which ones require a dynamic reloc.
+// * Write the dynamic relocations.
+// * Write the rest of the file.
+// This would have some drawbacks. For example, we would only know if .rela.dyn
+// is needed after applying relocations. If it is, it will go after rw and rx
+// sections. Given that it is ro, we will need an extra PT_LOAD. This
+// complicates things for the dynamic linker and means we would have to reserve
+// space for the extra PT_LOAD even if we end up not using it.
+template <class ELFT, class RelTy>
+static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
+  OffsetGetter GetOffset(Sec);
+
+  for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) {
+    const RelTy &Rel = *I;
+    SymbolBody &Body = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+    uint32_t Type = Rel.getType(Config->IsMips64EL);
+
+    if (Config->MipsN32Abi) {
+      uint32_t Processed;
+      std::tie(Type, Processed) =
+          mergeMipsN32RelTypes(Type, Rel.r_offset, I + 1, End);
+      I += Processed;
+    }
+
+    // Compute the offset of this section in the output section.
+    uint64_t Offset = GetOffset.get(Rel.r_offset);
+    if (Offset == uint64_t(-1))
+      continue;
+
+    // Report undefined symbols. The fact that we report undefined
+    // symbols here means that we report undefined symbols only when
+    // they have relocations pointing to them. We don't care about
+    // undefined symbols that are in dead-stripped sections.
+    if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak())
+      reportUndefined<ELFT>(Body, Sec, Rel.r_offset);
+
+    RelExpr Expr =
+        Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset);
+
+    // Ignore "hint" relocations because they are only markers for relaxation.
+    if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
+      continue;
+
+    bool Preemptible = isPreemptible(Body, Type);
+    Expr = adjustExpr<ELFT>(Body, Expr, Type, Sec.Data.data() + Rel.r_offset,
+                            Sec, Rel.r_offset);
+    if (ErrorCount)
+      continue;
+
+    // This relocation does not require got entry, but it is relative to got and
+    // needs it to be created. Here we request for that.
+    if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
+                       R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
+      InX::Got->HasGotOffRel = true;
+
+    // Read an addend.
+    int64_t Addend = computeAddend<ELFT>(Rel, Sec.Data.data());
+    if (Config->EMachine == EM_MIPS)
+      Addend += computeMipsAddend<ELFT>(Rel, Sec, Expr, Body, End);
+
+    // Process some TLS relocations, including relaxing TLS relocations.
+    // Note that this function does not handle all TLS relocations.
+    if (unsigned Processed =
+            handleTlsRelocation<ELFT>(Type, Body, Sec, Offset, Addend, Expr)) {
+      I += (Processed - 1);
+      continue;
+    }
+
+    // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+    if (needsPlt(Expr) && !Body.isInPlt()) {
+      if (Body.isGnuIFunc() && !Preemptible)
+        addPltEntry(InX::Iplt, InX::IgotPlt, In<ELFT>::RelaIplt,
+                    Target->IRelativeRel, Body, true);
+      else
+        addPltEntry(InX::Plt, InX::GotPlt, In<ELFT>::RelaPlt, Target->PltRel,
+                    Body, !Preemptible);
+    }
+
+    // Create a GOT slot if a relocation needs GOT.
+    if (needsGot(Expr)) {
+      if (Config->EMachine == EM_MIPS) {
+        // MIPS ABI has special rules to process GOT entries and doesn't
+        // require relocation entries for them. A special case is TLS
+        // relocations. In that case dynamic loader applies dynamic
+        // relocations to initialize TLS GOT entries.
+        // See "Global Offset Table" in Chapter 5 in the following document
+        // for detailed description:
+        // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+        InX::MipsGot->addEntry(Body, Addend, Expr);
+        if (Body.isTls() && Body.isPreemptible())
+          In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot,
+                                       Body.getGotOffset(), false, &Body, 0});
+      } else if (!Body.isInGot()) {
+        addGotEntry<ELFT>(Body, Preemptible);
+      }
+    }
+
+    if (!needsPlt(Expr) && !needsGot(Expr) && isPreemptible(Body, Type)) {
+      // We don't know anything about the finaly symbol. Just ask the dynamic
+      // linker to handle the relocation for us.
+      if (!Target->isPicRel(Type))
+        error("relocation " + toString(Type) +
+              " cannot be used against shared object; recompile with -fPIC" +
+              getLocation<ELFT>(Sec, Body, Offset));
+
+      In<ELFT>::RelaDyn->addReloc(
+          {Target->getDynRel(Type), &Sec, Offset, false, &Body, Addend});
+
+      // MIPS ABI turns using of GOT and dynamic relocations inside out.
+      // While regular ABI uses dynamic relocations to fill up GOT entries
+      // MIPS ABI requires dynamic linker to fills up GOT entries using
+      // specially sorted dynamic symbol table. This affects even dynamic
+      // relocations against symbols which do not require GOT entries
+      // creation explicitly, i.e. do not have any GOT-relocations. So if
+      // a preemptible symbol has a dynamic relocation we anyway have
+      // to create a GOT entry for it.
+      // If a non-preemptible symbol has a dynamic relocation against it,
+      // dynamic linker takes it st_value, adds offset and writes down
+      // result of the dynamic relocation. In case of preemptible symbol
+      // dynamic linker performs symbol resolution, writes the symbol value
+      // to the GOT entry and reads the GOT entry when it needs to perform
+      // a dynamic relocation.
+      // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
+      if (Config->EMachine == EM_MIPS)
+        InX::MipsGot->addEntry(Body, Addend, Expr);
+      continue;
+    }
+
+    // If the relocation points to something in the file, we can process it.
+    bool IsConstant =
+        isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset);
+
+    // The size is not going to change, so we fold it in here.
+    if (Expr == R_SIZE)
+      Addend += Body.getSize<ELFT>();
+
+    // If the output being produced is position independent, the final value
+    // is still not known. In that case we still need some help from the
+    // dynamic linker. We can however do better than just copying the incoming
+    // relocation. We can process some of it and and just ask the dynamic
+    // linker to add the load address.
+    if (!IsConstant)
+      In<ELFT>::RelaDyn->addReloc(
+          {Target->RelativeRel, &Sec, Offset, true, &Body, Addend});
+
+    // If the produced value is a constant, we just remember to write it
+    // when outputting this section. We also have to do it if the format
+    // uses Elf_Rel, since in that case the written value is the addend.
+    if (IsConstant || !RelTy::IsRela)
+      Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+  }
+}
+
+template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
+  if (S.AreRelocsRela)
+    scanRelocs<ELFT>(S, S.relas<ELFT>());
+  else
+    scanRelocs<ELFT>(S, S.rels<ELFT>());
+}
+
+// Insert the Thunks for OutputSection OS into their designated place
+// in the Sections vector, and recalculate the InputSection output section
+// offsets.
+// This may invalidate any output section offsets stored outside of InputSection
+void ThunkCreator::mergeThunks() {
+  for (auto &KV : ThunkSections) {
+    std::vector<InputSection *> *ISR = KV.first;
+    std::vector<ThunkSection *> &Thunks = KV.second;
+
+    // Order Thunks in ascending OutSecOff
+    auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) {
+      return A->OutSecOff < B->OutSecOff;
+    };
+    std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp);
+
+    // Merge sorted vectors of Thunks and InputSections by OutSecOff
+    std::vector<InputSection *> Tmp;
+    Tmp.reserve(ISR->size() + Thunks.size());
+    auto MergeCmp = [](const InputSection *A, const InputSection *B) {
+      // std::merge requires a strict weak ordering.
+      if (A->OutSecOff < B->OutSecOff)
+        return true;
+      if (A->OutSecOff == B->OutSecOff)
+        // Check if Thunk is immediately before any specific Target InputSection
+        // for example Mips LA25 Thunks.
+        if (auto *TA = dyn_cast<ThunkSection>(A))
+          if (TA && TA->getTargetInputSection() == B)
+            return true;
+      return false;
+    };
+    std::merge(ISR->begin(), ISR->end(), Thunks.begin(), Thunks.end(),
+               std::back_inserter(Tmp), MergeCmp);
+    *ISR = std::move(Tmp);
+  }
+}
+
+static uint32_t findEndOfFirstNonExec(OutputSectionCommand &Cmd) {
+  for (BaseCommand *Base : Cmd.Commands)
+    if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+      for (auto *IS : ISD->Sections)
+        if ((IS->Flags & SHF_EXECINSTR) == 0)
+          return IS->OutSecOff + IS->getSize();
+  return 0;
+}
+
+ThunkSection *ThunkCreator::getOSThunkSec(OutputSectionCommand *Cmd,
+                                          std::vector<InputSection *> *ISR) {
+  if (CurTS == nullptr) {
+    uint32_t Off = findEndOfFirstNonExec(*Cmd);
+    CurTS = addThunkSection(Cmd->Sec, ISR, Off);
+  }
+  return CurTS;
+}
+
+ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
+  ThunkSection *TS = ThunkedSections.lookup(IS);
+  if (TS)
+    return TS;
+  auto *TOS = IS->getParent();
+
+  // Find InputSectionRange within TOS that IS is in
+  OutputSectionCommand *C = Script->getCmd(TOS);
+  std::vector<InputSection *> *Range = nullptr;
+  for (BaseCommand *BC : C->Commands)
+    if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
+      InputSection *first = ISD->Sections.front();
+      InputSection *last = ISD->Sections.back();
+      if (IS->OutSecOff >= first->OutSecOff &&
+          IS->OutSecOff <= last->OutSecOff) {
+        Range = &ISD->Sections;
+        break;
+      }
+    }
+  TS = addThunkSection(TOS, Range, IS->OutSecOff);
+  ThunkedSections[IS] = TS;
+  return TS;
+}
+
+ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
+                                            std::vector<InputSection *> *ISR,
+                                            uint64_t Off) {
+  auto *TS = make<ThunkSection>(OS, Off);
+  ThunkSections[ISR].push_back(TS);
+  return TS;
+}
+
+std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
+                                                uint32_t Type) {
+  auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()});
+  if (!Res.second) {
+    // Check existing Thunks for Body to see if they can be reused
+    for (Thunk *ET : Res.first->second)
+      if (ET->isCompatibleWith(Type))
+        return std::make_pair(ET, false);
+  }
+  // No existing compatible Thunk in range, create a new one
+  Thunk *T = addThunk(Type, Body);
+  Res.first->second.push_back(T);
+  return std::make_pair(T, true);
+}
+
+// Call Fn on every executable InputSection accessed via the linker script
+// InputSectionDescription::Sections.
+void ThunkCreator::forEachExecInputSection(
+    ArrayRef<OutputSectionCommand *> OutputSections,
+    std::function<void(OutputSectionCommand *, std::vector<InputSection *> *,
+                       InputSection *)>
+        Fn) {
+  for (OutputSectionCommand *Cmd : OutputSections) {
+    OutputSection *OS = Cmd->Sec;
+    if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
+      continue;
+    for (BaseCommand *BC : Cmd->Commands)
+      if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
+        CurTS = nullptr;
+        for (InputSection *IS : ISD->Sections)
+          Fn(Cmd, &ISD->Sections, IS);
+      }
+  }
+}
+
+// Process all relocations from the InputSections that have been assigned
+// to OutputSections and redirect through Thunks if needed.
+//
+// createThunks must be called after scanRelocs has created the Relocations for
+// each InputSection. It must be called before the static symbol table is
+// finalized. If any Thunks are added to an OutputSection the output section
+// offsets of the InputSections will change.
+//
+// FIXME: All Thunks are assumed to be in range of the relocation. Range
+// extension Thunks are not yet supported.
+bool ThunkCreator::createThunks(
+    ArrayRef<OutputSectionCommand *> OutputSections) {
+  if (Pass > 0)
+    ThunkSections.clear();
+
+  // Create all the Thunks and insert them into synthetic ThunkSections. The
+  // ThunkSections are later inserted back into the OutputSection.
+
+  // We separate the creation of ThunkSections from the insertion of the
+  // ThunkSections back into the OutputSection as ThunkSections are not always
+  // inserted into the same OutputSection as the caller.
+  forEachExecInputSection(OutputSections, [&](OutputSectionCommand *Cmd,
+                                              std::vector<InputSection *> *ISR,
+                                              InputSection *IS) {
+    for (Relocation &Rel : IS->Relocations) {
+      SymbolBody &Body = *Rel.Sym;
+      if (Thunks.find(&Body) != Thunks.end() ||
+          !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body))
+        continue;
+      Thunk *T;
+      bool IsNew;
+      std::tie(T, IsNew) = getThunk(Body, Rel.Type);
+      if (IsNew) {
+        // Find or create a ThunkSection for the new Thunk
+        ThunkSection *TS;
+        if (auto *TIS = T->getTargetInputSection())
+          TS = getISThunkSec(TIS, Cmd->Sec);
+        else
+          TS = getOSThunkSec(Cmd, ISR);
+        TS->addThunk(T);
+        Thunks[T->ThunkSym] = T;
+      }
+      // Redirect relocation to Thunk, we never go via the PLT to a Thunk
+      Rel.Sym = T->ThunkSym;
+      Rel.Expr = fromPlt(Rel.Expr);
+    }
+  });
+  // Merge all created synthetic ThunkSections back into OutputSection
+  mergeThunks();
+  ++Pass;
+  return !ThunkSections.empty();
+}
+
+template void elf::scanRelocations<ELF32LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF32BE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64BE>(InputSectionBase &);
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
new file mode 100644 (file)
index 0000000..ea046d2
--- /dev/null
@@ -0,0 +1,185 @@
+//===- Relocations.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_RELOCATIONS_H
+#define LLD_ELF_RELOCATIONS_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <vector>
+
+namespace lld {
+namespace elf {
+class SymbolBody;
+class InputSection;
+class InputSectionBase;
+class OutputSection;
+struct OutputSectionCommand;
+
+// List of target-independent relocation types. Relocations read
+// from files are converted to these types so that the main code
+// doesn't have to know about architecture-specific details.
+enum RelExpr {
+  R_ABS,
+  R_ARM_SBREL,
+  R_GOT,
+  R_GOTONLY_PC,
+  R_GOTONLY_PC_FROM_END,
+  R_GOTREL,
+  R_GOTREL_FROM_END,
+  R_GOT_FROM_END,
+  R_GOT_OFF,
+  R_GOT_PAGE_PC,
+  R_GOT_PC,
+  R_HINT,
+  R_MIPS_GOTREL,
+  R_MIPS_GOT_GP,
+  R_MIPS_GOT_GP_PC,
+  R_MIPS_GOT_LOCAL_PAGE,
+  R_MIPS_GOT_OFF,
+  R_MIPS_GOT_OFF32,
+  R_MIPS_TLSGD,
+  R_MIPS_TLSLD,
+  R_NEG_TLS,
+  R_NONE,
+  R_PAGE_PC,
+  R_PC,
+  R_PLT,
+  R_PLT_PAGE_PC,
+  R_PLT_PC,
+  R_PPC_OPD,
+  R_PPC_PLT_OPD,
+  R_PPC_TOC,
+  R_RELAX_GOT_PC,
+  R_RELAX_GOT_PC_NOPIC,
+  R_RELAX_TLS_GD_TO_IE,
+  R_RELAX_TLS_GD_TO_IE_ABS,
+  R_RELAX_TLS_GD_TO_IE_END,
+  R_RELAX_TLS_GD_TO_IE_PAGE_PC,
+  R_RELAX_TLS_GD_TO_LE,
+  R_RELAX_TLS_GD_TO_LE_NEG,
+  R_RELAX_TLS_IE_TO_LE,
+  R_RELAX_TLS_LD_TO_LE,
+  R_SIZE,
+  R_TLS,
+  R_TLSDESC,
+  R_TLSDESC_CALL,
+  R_TLSDESC_PAGE,
+  R_TLSGD,
+  R_TLSGD_PC,
+  R_TLSLD,
+  R_TLSLD_PC,
+};
+
+// Build a bitmask with one bit set for each RelExpr.
+//
+// Constexpr function arguments can't be used in static asserts, so we
+// use template arguments to build the mask.
+// But function template partial specializations don't exist (needed
+// for base case of the recursion), so we need a dummy struct.
+template <RelExpr... Exprs> struct RelExprMaskBuilder {
+  static inline uint64_t build() { return 0; }
+};
+
+// Specialization for recursive case.
+template <RelExpr Head, RelExpr... Tail>
+struct RelExprMaskBuilder<Head, Tail...> {
+  static inline uint64_t build() {
+    static_assert(0 <= Head && Head < 64,
+                  "RelExpr is too large for 64-bit mask!");
+    return (uint64_t(1) << Head) | RelExprMaskBuilder<Tail...>::build();
+  }
+};
+
+// Return true if `Expr` is one of `Exprs`.
+// There are fewer than 64 RelExpr's, so we can represent any set of
+// RelExpr's as a constant bit mask and test for membership with a
+// couple cheap bitwise operations.
+template <RelExpr... Exprs> bool isRelExprOneOf(RelExpr Expr) {
+  assert(0 <= Expr && (int)Expr < 64 &&
+         "RelExpr is too large for 64-bit mask!");
+  return (uint64_t(1) << Expr) & RelExprMaskBuilder<Exprs...>::build();
+}
+
+// Architecture-neutral representation of relocation.
+struct Relocation {
+  RelExpr Expr;
+  uint32_t Type;
+  uint64_t Offset;
+  int64_t Addend;
+  SymbolBody *Sym;
+};
+
+template <class ELFT> void scanRelocations(InputSectionBase &);
+
+class ThunkSection;
+class Thunk;
+
+class ThunkCreator {
+public:
+  // Return true if Thunks have been added to OutputSections
+  bool createThunks(ArrayRef<OutputSectionCommand *> OutputSections);
+
+  // The number of completed passes of createThunks this permits us
+  // to do one time initialization on Pass 0 and put a limit on the
+  // number of times it can be called to prevent infinite loops.
+  uint32_t Pass = 0;
+
+private:
+  void mergeThunks();
+  ThunkSection *getOSThunkSec(OutputSectionCommand *Cmd,
+                              std::vector<InputSection *> *ISR);
+  ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS);
+  void forEachExecInputSection(
+      ArrayRef<OutputSectionCommand *> OutputSections,
+      std::function<void(OutputSectionCommand *, std::vector<InputSection *> *,
+                         InputSection *)>
+          Fn);
+  std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
+  ThunkSection *addThunkSection(OutputSection *OS,
+                                std::vector<InputSection *> *, uint64_t Off);
+  // Record all the available Thunks for a Symbol
+  llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols;
+
+  // Find a Thunk from the Thunks symbol definition, we can use this to find
+  // the Thunk from a relocation to the Thunks symbol definition.
+  llvm::DenseMap<SymbolBody *, Thunk *> Thunks;
+
+  // Track InputSections that have an inline ThunkSection placed in front
+  // an inline ThunkSection may have control fall through to the section below
+  // so we need to make sure that there is only one of them.
+  // The Mips LA25 Thunk is an example of an inline ThunkSection.
+  llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
+
+  // All the ThunkSections that we have created, organised by OutputSection
+  // will contain a mix of ThunkSections that have been created this pass, and
+  // ThunkSections that have been merged into the OutputSection on previous
+  // passes
+  std::map<std::vector<InputSection *> *, std::vector<ThunkSection *>>
+      ThunkSections;
+
+  // The ThunkSection for this vector of InputSections
+  ThunkSection *CurTS;
+};
+
+// Return a int64_t to make sure we get the sign extension out of the way as
+// early as possible.
+template <class ELFT>
+static inline int64_t getAddend(const typename ELFT::Rel &Rel) {
+  return 0;
+}
+template <class ELFT>
+static inline int64_t getAddend(const typename ELFT::Rela &Rel) {
+  return Rel.r_addend;
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp
new file mode 100644 (file)
index 0000000..86720de
--- /dev/null
@@ -0,0 +1,285 @@
+//===- ScriptLexer.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a lexer for the linker script.
+//
+// The linker script's grammar is not complex but ambiguous due to the
+// lack of the formal specification of the language. What we are trying to
+// do in this and other files in LLD is to make a "reasonable" linker
+// script processor.
+//
+// Among simplicity, compatibility and efficiency, we put the most
+// emphasis on simplicity when we wrote this lexer. Compatibility with the
+// GNU linkers is important, but we did not try to clone every tiny corner
+// case of their lexers, as even ld.bfd and ld.gold are subtly different
+// in various corner cases. We do not care much about efficiency because
+// the time spent in parsing linker scripts is usually negligible.
+//
+// Our grammar of the linker script is LL(2), meaning that it needs at
+// most two-token lookahead to parse. The only place we need two-token
+// lookahead is labels in version scripts, where we need to parse "local :"
+// as if "local:".
+//
+// Overall, this lexer works fine for most linker scripts. There might
+// be room for improving compatibility, but that's probably not at the
+// top of our todo list.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptLexer.h"
+#include "Error.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns a whole line containing the current token.
+StringRef ScriptLexer::getLine() {
+  StringRef S = getCurrentMB().getBuffer();
+  StringRef Tok = Tokens[Pos - 1];
+
+  size_t Pos = S.rfind('\n', Tok.data() - S.data());
+  if (Pos != StringRef::npos)
+    S = S.substr(Pos + 1);
+  return S.substr(0, S.find_first_of("\r\n"));
+}
+
+// Returns 1-based line number of the current token.
+size_t ScriptLexer::getLineNumber() {
+  StringRef S = getCurrentMB().getBuffer();
+  StringRef Tok = Tokens[Pos - 1];
+  return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
+}
+
+// Returns 0-based column number of the current token.
+size_t ScriptLexer::getColumnNumber() {
+  StringRef Tok = Tokens[Pos - 1];
+  return Tok.data() - getLine().data();
+}
+
+std::string ScriptLexer::getCurrentLocation() {
+  std::string Filename = getCurrentMB().getBufferIdentifier();
+  if (!Pos)
+    return Filename;
+  return (Filename + ":" + Twine(getLineNumber())).str();
+}
+
+ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); }
+
+// We don't want to record cascading errors. Keep only the first one.
+void ScriptLexer::setError(const Twine &Msg) {
+  if (Error)
+    return;
+  Error = true;
+
+  if (!Pos) {
+    error(getCurrentLocation() + ": " + Msg);
+    return;
+  }
+
+  std::string S = getCurrentLocation() + ": ";
+  error(S + Msg);
+  error(S + getLine());
+  error(S + std::string(getColumnNumber(), ' ') + "^");
+}
+
+// Split S into linker script tokens.
+void ScriptLexer::tokenize(MemoryBufferRef MB) {
+  std::vector<StringRef> Vec;
+  MBs.push_back(MB);
+  StringRef S = MB.getBuffer();
+  StringRef Begin = S;
+
+  for (;;) {
+    S = skipSpace(S);
+    if (S.empty())
+      break;
+
+    // Quoted token. Note that double-quote characters are parts of a token
+    // because, in a glob match context, only unquoted tokens are interpreted
+    // as glob patterns. Double-quoted tokens are literal patterns in that
+    // context.
+    if (S.startswith("\"")) {
+      size_t E = S.find("\"", 1);
+      if (E == StringRef::npos) {
+        StringRef Filename = MB.getBufferIdentifier();
+        size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
+        error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
+        return;
+      }
+
+      Vec.push_back(S.take_front(E + 1));
+      S = S.substr(E + 1);
+      continue;
+    }
+
+    // Unquoted token. This is more relaxed than tokens in C-like language,
+    // so that you can write "file-name.cpp" as one bare token, for example.
+    size_t Pos = S.find_first_not_of(
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+        "0123456789_.$/\\~=+[]*?-!<>^:");
+
+    // A character that cannot start a word (which is usually a
+    // punctuation) forms a single character token.
+    if (Pos == 0)
+      Pos = 1;
+    Vec.push_back(S.substr(0, Pos));
+    S = S.substr(Pos);
+  }
+
+  Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
+}
+
+// Skip leading whitespace characters or comments.
+StringRef ScriptLexer::skipSpace(StringRef S) {
+  for (;;) {
+    if (S.startswith("/*")) {
+      size_t E = S.find("*/", 2);
+      if (E == StringRef::npos) {
+        error("unclosed comment in a linker script");
+        return "";
+      }
+      S = S.substr(E + 2);
+      continue;
+    }
+    if (S.startswith("#")) {
+      size_t E = S.find('\n', 1);
+      if (E == StringRef::npos)
+        E = S.size() - 1;
+      S = S.substr(E + 1);
+      continue;
+    }
+    size_t Size = S.size();
+    S = S.ltrim();
+    if (S.size() == Size)
+      return S;
+  }
+}
+
+// An erroneous token is handled as if it were the last token before EOF.
+bool ScriptLexer::atEOF() { return Error || Tokens.size() == Pos; }
+
+// Split a given string as an expression.
+// This function returns "3", "*" and "5" for "3*5" for example.
+static std::vector<StringRef> tokenizeExpr(StringRef S) {
+  StringRef Ops = "+-*/:"; // List of operators
+
+  // Quoted strings are literal strings, so we don't want to split it.
+  if (S.startswith("\""))
+    return {S};
+
+  // Split S with +-*/ as separators.
+  std::vector<StringRef> Ret;
+  while (!S.empty()) {
+    size_t E = S.find_first_of(Ops);
+
+    // No need to split if there is no operator.
+    if (E == StringRef::npos) {
+      Ret.push_back(S);
+      break;
+    }
+
+    // Get a token before the opreator.
+    if (E != 0)
+      Ret.push_back(S.substr(0, E));
+
+    // Get the operator as a token.
+    Ret.push_back(S.substr(E, 1));
+    S = S.substr(E + 1);
+  }
+  return Ret;
+}
+
+// In contexts where expressions are expected, the lexer should apply
+// different tokenization rules than the default one. By default,
+// arithmetic operator characters are regular characters, but in the
+// expression context, they should be independent tokens.
+//
+// For example, "foo*3" should be tokenized to "foo", "*" and "3" only
+// in the expression context.
+//
+// This function may split the current token into multiple tokens.
+void ScriptLexer::maybeSplitExpr() {
+  if (!InExpr || Error || atEOF())
+    return;
+
+  std::vector<StringRef> V = tokenizeExpr(Tokens[Pos]);
+  if (V.size() == 1)
+    return;
+  Tokens.erase(Tokens.begin() + Pos);
+  Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
+}
+
+StringRef ScriptLexer::next() {
+  maybeSplitExpr();
+
+  if (Error)
+    return "";
+  if (atEOF()) {
+    setError("unexpected EOF");
+    return "";
+  }
+  return Tokens[Pos++];
+}
+
+StringRef ScriptLexer::peek() {
+  StringRef Tok = next();
+  if (Error)
+    return "";
+  Pos = Pos - 1;
+  return Tok;
+}
+
+bool ScriptLexer::consume(StringRef Tok) {
+  if (peek() == Tok) {
+    skip();
+    return true;
+  }
+  return false;
+}
+
+// Consumes Tok followed by ":". Space is allowed between Tok and ":".
+bool ScriptLexer::consumeLabel(StringRef Tok) {
+  if (consume((Tok + ":").str()))
+    return true;
+  if (Tokens.size() >= Pos + 2 && Tokens[Pos] == Tok &&
+      Tokens[Pos + 1] == ":") {
+    Pos += 2;
+    return true;
+  }
+  return false;
+}
+
+void ScriptLexer::skip() { (void)next(); }
+
+void ScriptLexer::expect(StringRef Expect) {
+  if (Error)
+    return;
+  StringRef Tok = next();
+  if (Tok != Expect)
+    setError(Expect + " expected, but got " + Tok);
+}
+
+// Returns true if S encloses T.
+static bool encloses(StringRef S, StringRef T) {
+  return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end();
+}
+
+MemoryBufferRef ScriptLexer::getCurrentMB() {
+  // Find input buffer containing the current token.
+  assert(!MBs.empty());
+  if (!Pos)
+    return MBs[0];
+
+  for (MemoryBufferRef MB : MBs)
+    if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
+      return MB;
+  llvm_unreachable("getCurrentMB: failed to find a token");
+}
diff --git a/ELF/ScriptLexer.h b/ELF/ScriptLexer.h
new file mode 100644 (file)
index 0000000..64d6d92
--- /dev/null
@@ -0,0 +1,56 @@
+//===- ScriptLexer.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_LEXER_H
+#define LLD_ELF_SCRIPT_LEXER_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class ScriptLexer {
+public:
+  explicit ScriptLexer(MemoryBufferRef MB);
+
+  void setError(const Twine &Msg);
+  void tokenize(MemoryBufferRef MB);
+  static StringRef skipSpace(StringRef S);
+  bool atEOF();
+  StringRef next();
+  StringRef peek();
+  void skip();
+  bool consume(StringRef Tok);
+  void expect(StringRef Expect);
+  bool consumeLabel(StringRef Tok);
+  std::string getCurrentLocation();
+
+  std::vector<MemoryBufferRef> MBs;
+  std::vector<StringRef> Tokens;
+  bool InExpr = false;
+  size_t Pos = 0;
+  bool Error = false;
+
+private:
+  void maybeSplitExpr();
+  StringRef getLine();
+  size_t getLineNumber();
+  size_t getColumnNumber();
+
+  MemoryBufferRef getCurrentMB();
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
new file mode 100644 (file)
index 0000000..b384708
--- /dev/null
@@ -0,0 +1,1247 @@
+//===- ScriptParser.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a recursive-descendent parser for linker scripts.
+// Parsed results are stored to Config and Script global objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptParser.h"
+#include "Config.h"
+#include "Driver.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "ScriptLexer.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <cassert>
+#include <limits>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::elf;
+
+static bool isUnderSysroot(StringRef Path);
+
+namespace {
+class ScriptParser final : ScriptLexer {
+public:
+  ScriptParser(MemoryBufferRef MB)
+      : ScriptLexer(MB),
+        IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {}
+
+  void readLinkerScript();
+  void readVersionScript();
+  void readDynamicList();
+
+private:
+  void addFile(StringRef Path);
+  OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation);
+
+  void readAsNeeded();
+  void readEntry();
+  void readExtern();
+  void readGroup();
+  void readInclude();
+  void readMemory();
+  void readOutput();
+  void readOutputArch();
+  void readOutputFormat();
+  void readPhdrs();
+  void readSearchDir();
+  void readSections();
+  void readVersion();
+  void readVersionScriptCommand();
+
+  SymbolAssignment *readAssignment(StringRef Name);
+  BytesDataCommand *readBytesDataCommand(StringRef Tok);
+  uint32_t readFill();
+  uint32_t parseFill(StringRef Tok);
+  void readSectionAddressType(OutputSectionCommand *Cmd);
+  OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
+  std::vector<StringRef> readOutputSectionPhdrs();
+  InputSectionDescription *readInputSectionDescription(StringRef Tok);
+  StringMatcher readFilePatterns();
+  std::vector<SectionPattern> readInputSectionsList();
+  InputSectionDescription *readInputSectionRules(StringRef FilePattern);
+  unsigned readPhdrType();
+  SortSectionPolicy readSortKind();
+  SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
+  SymbolAssignment *readProvideOrAssignment(StringRef Tok);
+  void readSort();
+  AssertCommand *readAssert();
+  Expr readAssertExpr();
+
+  uint64_t readMemoryAssignment(StringRef, StringRef, StringRef);
+  std::pair<uint32_t, uint32_t> readMemoryAttributes();
+
+  Expr readExpr();
+  Expr readExpr1(Expr Lhs, int MinPrec);
+  StringRef readParenLiteral();
+  Expr readPrimary();
+  Expr readTernary(Expr Cond);
+  Expr readParenExpr();
+
+  // For parsing version script.
+  std::vector<SymbolVersion> readVersionExtern();
+  void readAnonymousDeclaration();
+  void readVersionDeclaration(StringRef VerStr);
+
+  std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>>
+  readSymbols();
+
+  bool IsUnderSysroot;
+};
+} // namespace
+
+static StringRef unquote(StringRef S) {
+  if (S.startswith("\""))
+    return S.substr(1, S.size() - 2);
+  return S;
+}
+
+static bool isUnderSysroot(StringRef Path) {
+  if (Config->Sysroot == "")
+    return false;
+  for (; !Path.empty(); Path = sys::path::parent_path(Path))
+    if (sys::fs::equivalent(Config->Sysroot, Path))
+      return true;
+  return false;
+}
+
+// Some operations only support one non absolute value. Move the
+// absolute one to the right hand side for convenience.
+static void moveAbsRight(ExprValue &A, ExprValue &B) {
+  if (A.isAbsolute())
+    std::swap(A, B);
+  if (!B.isAbsolute())
+    error(A.Loc + ": at least one side of the expression must be absolute");
+}
+
+static ExprValue add(ExprValue A, ExprValue B) {
+  moveAbsRight(A, B);
+  return {A.Sec, A.ForceAbsolute, A.Val + B.getValue(), A.Loc};
+}
+
+static ExprValue sub(ExprValue A, ExprValue B) {
+  return {A.Sec, A.Val - B.getValue(), A.Loc};
+}
+
+static ExprValue mul(ExprValue A, ExprValue B) {
+  return A.getValue() * B.getValue();
+}
+
+static ExprValue div(ExprValue A, ExprValue B) {
+  if (uint64_t BV = B.getValue())
+    return A.getValue() / BV;
+  error("division by zero");
+  return 0;
+}
+
+static ExprValue bitAnd(ExprValue A, ExprValue B) {
+  moveAbsRight(A, B);
+  return {A.Sec, A.ForceAbsolute,
+          (A.getValue() & B.getValue()) - A.getSecAddr(), A.Loc};
+}
+
+static ExprValue bitOr(ExprValue A, ExprValue B) {
+  moveAbsRight(A, B);
+  return {A.Sec, A.ForceAbsolute,
+          (A.getValue() | B.getValue()) - A.getSecAddr(), A.Loc};
+}
+
+void ScriptParser::readDynamicList() {
+  expect("{");
+  readAnonymousDeclaration();
+  if (!atEOF())
+    setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScript() {
+  readVersionScriptCommand();
+  if (!atEOF())
+    setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScriptCommand() {
+  if (consume("{")) {
+    readAnonymousDeclaration();
+    return;
+  }
+
+  while (!atEOF() && !Error && peek() != "}") {
+    StringRef VerStr = next();
+    if (VerStr == "{") {
+      setError("anonymous version definition is used in "
+               "combination with other version definitions");
+      return;
+    }
+    expect("{");
+    readVersionDeclaration(VerStr);
+  }
+}
+
+void ScriptParser::readVersion() {
+  expect("{");
+  readVersionScriptCommand();
+  expect("}");
+}
+
+void ScriptParser::readLinkerScript() {
+  while (!atEOF()) {
+    StringRef Tok = next();
+    if (Tok == ";")
+      continue;
+
+    if (Tok == "ASSERT") {
+      Script->Opt.Commands.push_back(readAssert());
+    } else if (Tok == "ENTRY") {
+      readEntry();
+    } else if (Tok == "EXTERN") {
+      readExtern();
+    } else if (Tok == "GROUP" || Tok == "INPUT") {
+      readGroup();
+    } else if (Tok == "INCLUDE") {
+      readInclude();
+    } else if (Tok == "MEMORY") {
+      readMemory();
+    } else if (Tok == "OUTPUT") {
+      readOutput();
+    } else if (Tok == "OUTPUT_ARCH") {
+      readOutputArch();
+    } else if (Tok == "OUTPUT_FORMAT") {
+      readOutputFormat();
+    } else if (Tok == "PHDRS") {
+      readPhdrs();
+    } else if (Tok == "SEARCH_DIR") {
+      readSearchDir();
+    } else if (Tok == "SECTIONS") {
+      readSections();
+    } else if (Tok == "VERSION") {
+      readVersion();
+    } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
+      Script->Opt.Commands.push_back(Cmd);
+    } else {
+      setError("unknown directive: " + Tok);
+    }
+  }
+}
+
+void ScriptParser::addFile(StringRef S) {
+  if (IsUnderSysroot && S.startswith("/")) {
+    SmallString<128> PathData;
+    StringRef Path = (Config->Sysroot + S).toStringRef(PathData);
+    if (sys::fs::exists(Path)) {
+      Driver->addFile(Saver.save(Path), /*WithLOption=*/false);
+      return;
+    }
+  }
+
+  if (sys::path::is_absolute(S)) {
+    Driver->addFile(S, /*WithLOption=*/false);
+  } else if (S.startswith("=")) {
+    if (Config->Sysroot.empty())
+      Driver->addFile(S.substr(1), /*WithLOption=*/false);
+    else
+      Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)),
+                      /*WithLOption=*/false);
+  } else if (S.startswith("-l")) {
+    Driver->addLibrary(S.substr(2));
+  } else if (sys::fs::exists(S)) {
+    Driver->addFile(S, /*WithLOption=*/false);
+  } else {
+    if (Optional<std::string> Path = findFromSearchPaths(S))
+      Driver->addFile(Saver.save(*Path), /*WithLOption=*/true);
+    else
+      setError("unable to find " + S);
+  }
+}
+
+void ScriptParser::readAsNeeded() {
+  expect("(");
+  bool Orig = Config->AsNeeded;
+  Config->AsNeeded = true;
+  while (!Error && !consume(")"))
+    addFile(unquote(next()));
+  Config->AsNeeded = Orig;
+}
+
+void ScriptParser::readEntry() {
+  // -e <symbol> takes predecence over ENTRY(<symbol>).
+  expect("(");
+  StringRef Tok = next();
+  if (Config->Entry.empty())
+    Config->Entry = Tok;
+  expect(")");
+}
+
+void ScriptParser::readExtern() {
+  expect("(");
+  while (!Error && !consume(")"))
+    Config->Undefined.push_back(next());
+}
+
+void ScriptParser::readGroup() {
+  expect("(");
+  while (!Error && !consume(")")) {
+    if (consume("AS_NEEDED"))
+      readAsNeeded();
+    else
+      addFile(unquote(next()));
+  }
+}
+
+void ScriptParser::readInclude() {
+  StringRef Tok = unquote(next());
+
+  // https://sourceware.org/binutils/docs/ld/File-Commands.html:
+  // The file will be searched for in the current directory, and in any
+  // directory specified with the -L option.
+  if (sys::fs::exists(Tok)) {
+    if (Optional<MemoryBufferRef> MB = readFile(Tok))
+      tokenize(*MB);
+    return;
+  }
+  if (Optional<std::string> Path = findFromSearchPaths(Tok)) {
+    if (Optional<MemoryBufferRef> MB = readFile(*Path))
+      tokenize(*MB);
+    return;
+  }
+  setError("cannot open " + Tok);
+}
+
+void ScriptParser::readOutput() {
+  // -o <file> takes predecence over OUTPUT(<file>).
+  expect("(");
+  StringRef Tok = next();
+  if (Config->OutputFile.empty())
+    Config->OutputFile = unquote(Tok);
+  expect(")");
+}
+
+void ScriptParser::readOutputArch() {
+  // OUTPUT_ARCH is ignored for now.
+  expect("(");
+  while (!Error && !consume(")"))
+    skip();
+}
+
+void ScriptParser::readOutputFormat() {
+  // Error checking only for now.
+  expect("(");
+  skip();
+  if (consume(")"))
+    return;
+  expect(",");
+  skip();
+  expect(",");
+  skip();
+  expect(")");
+}
+
+void ScriptParser::readPhdrs() {
+  expect("{");
+  while (!Error && !consume("}")) {
+    Script->Opt.PhdrsCommands.push_back(
+        {next(), PT_NULL, false, false, UINT_MAX, nullptr});
+
+    PhdrsCommand &PhdrCmd = Script->Opt.PhdrsCommands.back();
+    PhdrCmd.Type = readPhdrType();
+
+    while (!Error && !consume(";")) {
+      if (consume("FILEHDR"))
+        PhdrCmd.HasFilehdr = true;
+      else if (consume("PHDRS"))
+        PhdrCmd.HasPhdrs = true;
+      else if (consume("AT"))
+        PhdrCmd.LMAExpr = readParenExpr();
+      else if (consume("FLAGS"))
+        PhdrCmd.Flags = readParenExpr()().getValue();
+      else
+        setError("unexpected header attribute: " + next());
+    }
+  }
+}
+
+void ScriptParser::readSearchDir() {
+  expect("(");
+  StringRef Tok = next();
+  if (!Config->Nostdlib)
+    Config->SearchPaths.push_back(unquote(Tok));
+  expect(")");
+}
+
+void ScriptParser::readSections() {
+  Script->Opt.HasSections = true;
+
+  // -no-rosegment is used to avoid placing read only non-executable sections in
+  // their own segment. We do the same if SECTIONS command is present in linker
+  // script. See comment for computeFlags().
+  Config->SingleRoRx = true;
+
+  expect("{");
+  while (!Error && !consume("}")) {
+    StringRef Tok = next();
+    BaseCommand *Cmd = readProvideOrAssignment(Tok);
+    if (!Cmd) {
+      if (Tok == "ASSERT")
+        Cmd = readAssert();
+      else
+        Cmd = readOutputSectionDescription(Tok);
+    }
+    Script->Opt.Commands.push_back(Cmd);
+  }
+}
+
+static int precedence(StringRef Op) {
+  return StringSwitch<int>(Op)
+      .Cases("*", "/", 5)
+      .Cases("+", "-", 4)
+      .Cases("<<", ">>", 3)
+      .Cases("<", "<=", ">", ">=", "==", "!=", 2)
+      .Cases("&", "|", 1)
+      .Default(-1);
+}
+
+StringMatcher ScriptParser::readFilePatterns() {
+  std::vector<StringRef> V;
+  while (!Error && !consume(")"))
+    V.push_back(next());
+  return StringMatcher(V);
+}
+
+SortSectionPolicy ScriptParser::readSortKind() {
+  if (consume("SORT") || consume("SORT_BY_NAME"))
+    return SortSectionPolicy::Name;
+  if (consume("SORT_BY_ALIGNMENT"))
+    return SortSectionPolicy::Alignment;
+  if (consume("SORT_BY_INIT_PRIORITY"))
+    return SortSectionPolicy::Priority;
+  if (consume("SORT_NONE"))
+    return SortSectionPolicy::None;
+  return SortSectionPolicy::Default;
+}
+
+// Reads SECTIONS command contents in the following form:
+//
+// <contents> ::= <elem>*
+// <elem>     ::= <exclude>? <glob-pattern>
+// <exclude>  ::= "EXCLUDE_FILE" "(" <glob-pattern>+ ")"
+//
+// For example,
+//
+// *(.foo EXCLUDE_FILE (a.o) .bar EXCLUDE_FILE (b.o) .baz)
+//
+// is parsed as ".foo", ".bar" with "a.o", and ".baz" with "b.o".
+// The semantics of that is section .foo in any file, section .bar in
+// any file but a.o, and section .baz in any file but b.o.
+std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
+  std::vector<SectionPattern> Ret;
+  while (!Error && peek() != ")") {
+    StringMatcher ExcludeFilePat;
+    if (consume("EXCLUDE_FILE")) {
+      expect("(");
+      ExcludeFilePat = readFilePatterns();
+    }
+
+    std::vector<StringRef> V;
+    while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE")
+      V.push_back(next());
+
+    if (!V.empty())
+      Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)});
+    else
+      setError("section pattern is expected");
+  }
+  return Ret;
+}
+
+// Reads contents of "SECTIONS" directive. That directive contains a
+// list of glob patterns for input sections. The grammar is as follows.
+//
+// <patterns> ::= <section-list>
+//              | <sort> "(" <section-list> ")"
+//              | <sort> "(" <sort> "(" <section-list> ")" ")"
+//
+// <sort>     ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
+//              | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
+//
+// <section-list> is parsed by readInputSectionsList().
+InputSectionDescription *
+ScriptParser::readInputSectionRules(StringRef FilePattern) {
+  auto *Cmd = make<InputSectionDescription>(FilePattern);
+  expect("(");
+
+  while (!Error && !consume(")")) {
+    SortSectionPolicy Outer = readSortKind();
+    SortSectionPolicy Inner = SortSectionPolicy::Default;
+    std::vector<SectionPattern> V;
+    if (Outer != SortSectionPolicy::Default) {
+      expect("(");
+      Inner = readSortKind();
+      if (Inner != SortSectionPolicy::Default) {
+        expect("(");
+        V = readInputSectionsList();
+        expect(")");
+      } else {
+        V = readInputSectionsList();
+      }
+      expect(")");
+    } else {
+      V = readInputSectionsList();
+    }
+
+    for (SectionPattern &Pat : V) {
+      Pat.SortInner = Inner;
+      Pat.SortOuter = Outer;
+    }
+
+    std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
+  }
+  return Cmd;
+}
+
+InputSectionDescription *
+ScriptParser::readInputSectionDescription(StringRef Tok) {
+  // Input section wildcard can be surrounded by KEEP.
+  // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
+  if (Tok == "KEEP") {
+    expect("(");
+    StringRef FilePattern = next();
+    InputSectionDescription *Cmd = readInputSectionRules(FilePattern);
+    expect(")");
+    Script->Opt.KeptSections.push_back(Cmd);
+    return Cmd;
+  }
+  return readInputSectionRules(Tok);
+}
+
+void ScriptParser::readSort() {
+  expect("(");
+  expect("CONSTRUCTORS");
+  expect(")");
+}
+
+AssertCommand *ScriptParser::readAssert() {
+  return make<AssertCommand>(readAssertExpr());
+}
+
+Expr ScriptParser::readAssertExpr() {
+  expect("(");
+  Expr E = readExpr();
+  expect(",");
+  StringRef Msg = unquote(next());
+  expect(")");
+
+  return [=] {
+    if (!E().getValue())
+      error(Msg);
+    return Script->getDot();
+  };
+}
+
+// Reads a FILL(expr) command. We handle the FILL command as an
+// alias for =fillexp section attribute, which is different from
+// what GNU linkers do.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
+uint32_t ScriptParser::readFill() {
+  expect("(");
+  uint32_t V = parseFill(next());
+  expect(")");
+  return V;
+}
+
+// Reads an expression and/or the special directive "(NOLOAD)" for an
+// output section definition.
+//
+// An output section name can be followed by an address expression
+// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be
+// interpreted as either the beginning of some expression or "(NOLOAD)".
+//
+// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
+// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
+void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) {
+  if (consume("(")) {
+    if (consume("NOLOAD")) {
+      expect(")");
+      Cmd->Noload = true;
+      return;
+    }
+    Cmd->AddrExpr = readExpr();
+    expect(")");
+  } else {
+    Cmd->AddrExpr = readExpr();
+  }
+
+  if (consume("(")) {
+    expect("NOLOAD");
+    expect(")");
+    Cmd->Noload = true;
+  }
+}
+
+OutputSectionCommand *
+ScriptParser::readOutputSectionDescription(StringRef OutSec) {
+  OutputSectionCommand *Cmd =
+      Script->createOutputSectionCommand(OutSec, getCurrentLocation());
+
+  if (peek() != ":")
+    readSectionAddressType(Cmd);
+  expect(":");
+
+  if (consume("AT"))
+    Cmd->LMAExpr = readParenExpr();
+  if (consume("ALIGN"))
+    Cmd->AlignExpr = readParenExpr();
+  if (consume("SUBALIGN"))
+    Cmd->SubalignExpr = readParenExpr();
+
+  // Parse constraints.
+  if (consume("ONLY_IF_RO"))
+    Cmd->Constraint = ConstraintKind::ReadOnly;
+  if (consume("ONLY_IF_RW"))
+    Cmd->Constraint = ConstraintKind::ReadWrite;
+  expect("{");
+
+  while (!Error && !consume("}")) {
+    StringRef Tok = next();
+    if (Tok == ";") {
+      // Empty commands are allowed. Do nothing here.
+    } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) {
+      Cmd->Commands.push_back(Assign);
+    } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) {
+      Cmd->Commands.push_back(Data);
+    } else if (Tok == "ASSERT") {
+      Cmd->Commands.push_back(readAssert());
+      expect(";");
+    } else if (Tok == "CONSTRUCTORS") {
+      // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
+      // by name. This is for very old file formats such as ECOFF/XCOFF.
+      // For ELF, we should ignore.
+    } else if (Tok == "FILL") {
+      Cmd->Filler = readFill();
+    } else if (Tok == "SORT") {
+      readSort();
+    } else if (peek() == "(") {
+      Cmd->Commands.push_back(readInputSectionDescription(Tok));
+    } else {
+      setError("unknown command " + Tok);
+    }
+  }
+
+  if (consume(">"))
+    Cmd->MemoryRegionName = next();
+
+  Cmd->Phdrs = readOutputSectionPhdrs();
+
+  if (consume("="))
+    Cmd->Filler = parseFill(next());
+  else if (peek().startswith("="))
+    Cmd->Filler = parseFill(next().drop_front());
+
+  // Consume optional comma following output section command.
+  consume(",");
+
+  return Cmd;
+}
+
+// Parses a given string as a octal/decimal/hexadecimal number and
+// returns it as a big-endian number. Used for `=<fillexp>`.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
+//
+// When reading a hexstring, ld.bfd handles it as a blob of arbitrary
+// size, while ld.gold always handles it as a 32-bit big-endian number.
+// We are compatible with ld.gold because it's easier to implement.
+uint32_t ScriptParser::parseFill(StringRef Tok) {
+  uint32_t V = 0;
+  if (!to_integer(Tok, V))
+    setError("invalid filler expression: " + Tok);
+
+  uint32_t Buf;
+  write32be(&Buf, V);
+  return Buf;
+}
+
+SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
+  expect("(");
+  SymbolAssignment *Cmd = readAssignment(next());
+  Cmd->Provide = Provide;
+  Cmd->Hidden = Hidden;
+  expect(")");
+  expect(";");
+  return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+  SymbolAssignment *Cmd = nullptr;
+  if (peek() == "=" || peek() == "+=") {
+    Cmd = readAssignment(Tok);
+    expect(";");
+  } else if (Tok == "PROVIDE") {
+    Cmd = readProvideHidden(true, false);
+  } else if (Tok == "HIDDEN") {
+    Cmd = readProvideHidden(false, true);
+  } else if (Tok == "PROVIDE_HIDDEN") {
+    Cmd = readProvideHidden(true, true);
+  }
+  return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
+  StringRef Op = next();
+  assert(Op == "=" || Op == "+=");
+  Expr E = readExpr();
+  if (Op == "+=") {
+    std::string Loc = getCurrentLocation();
+    E = [=] { return add(Script->getSymbolValue(Loc, Name), E()); };
+  }
+  return make<SymbolAssignment>(Name, E, getCurrentLocation());
+}
+
+// This is an operator-precedence parser to parse a linker
+// script expression.
+Expr ScriptParser::readExpr() {
+  // Our lexer is context-aware. Set the in-expression bit so that
+  // they apply different tokenization rules.
+  bool Orig = InExpr;
+  InExpr = true;
+  Expr E = readExpr1(readPrimary(), 0);
+  InExpr = Orig;
+  return E;
+}
+
+static Expr combine(StringRef Op, Expr L, Expr R) {
+  if (Op == "+")
+    return [=] { return add(L(), R()); };
+  if (Op == "-")
+    return [=] { return sub(L(), R()); };
+  if (Op == "*")
+    return [=] { return mul(L(), R()); };
+  if (Op == "/")
+    return [=] { return div(L(), R()); };
+  if (Op == "<<")
+    return [=] { return L().getValue() << R().getValue(); };
+  if (Op == ">>")
+    return [=] { return L().getValue() >> R().getValue(); };
+  if (Op == "<")
+    return [=] { return L().getValue() < R().getValue(); };
+  if (Op == ">")
+    return [=] { return L().getValue() > R().getValue(); };
+  if (Op == ">=")
+    return [=] { return L().getValue() >= R().getValue(); };
+  if (Op == "<=")
+    return [=] { return L().getValue() <= R().getValue(); };
+  if (Op == "==")
+    return [=] { return L().getValue() == R().getValue(); };
+  if (Op == "!=")
+    return [=] { return L().getValue() != R().getValue(); };
+  if (Op == "&")
+    return [=] { return bitAnd(L(), R()); };
+  if (Op == "|")
+    return [=] { return bitOr(L(), R()); };
+  llvm_unreachable("invalid operator");
+}
+
+// This is a part of the operator-precedence parser. This function
+// assumes that the remaining token stream starts with an operator.
+Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
+  while (!atEOF() && !Error) {
+    // Read an operator and an expression.
+    if (consume("?"))
+      return readTernary(Lhs);
+    StringRef Op1 = peek();
+    if (precedence(Op1) < MinPrec)
+      break;
+    skip();
+    Expr Rhs = readPrimary();
+
+    // Evaluate the remaining part of the expression first if the
+    // next operator has greater precedence than the previous one.
+    // For example, if we have read "+" and "3", and if the next
+    // operator is "*", then we'll evaluate 3 * ... part first.
+    while (!atEOF()) {
+      StringRef Op2 = peek();
+      if (precedence(Op2) <= precedence(Op1))
+        break;
+      Rhs = readExpr1(Rhs, precedence(Op2));
+    }
+
+    Lhs = combine(Op1, Lhs, Rhs);
+  }
+  return Lhs;
+}
+
+uint64_t static getConstant(StringRef S) {
+  if (S == "COMMONPAGESIZE")
+    return Target->PageSize;
+  if (S == "MAXPAGESIZE")
+    return Config->MaxPageSize;
+  error("unknown constant: " + S);
+  return 0;
+}
+
+// Parses Tok as an integer. It recognizes hexadecimal (prefixed with
+// "0x" or suffixed with "H") and decimal numbers. Decimal numbers may
+// have "K" (Ki) or "M" (Mi) suffixes.
+static Optional<uint64_t> parseInt(StringRef Tok) {
+  // Negative number
+  if (Tok.startswith("-")) {
+    if (Optional<uint64_t> Val = parseInt(Tok.substr(1)))
+      return -*Val;
+    return None;
+  }
+
+  // Hexadecimal
+  uint64_t Val;
+  if (Tok.startswith_lower("0x") && to_integer(Tok.substr(2), Val, 16))
+    return Val;
+  if (Tok.endswith_lower("H") && to_integer(Tok.drop_back(), Val, 16))
+    return Val;
+
+  // Decimal
+  if (Tok.endswith_lower("K")) {
+    if (!to_integer(Tok.drop_back(), Val, 10))
+      return None;
+    return Val * 1024;
+  }
+  if (Tok.endswith_lower("M")) {
+    if (!to_integer(Tok.drop_back(), Val, 10))
+      return None;
+    return Val * 1024 * 1024;
+  }
+  if (!to_integer(Tok, Val, 10))
+    return None;
+  return Val;
+}
+
+BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) {
+  int Size = StringSwitch<int>(Tok)
+                 .Case("BYTE", 1)
+                 .Case("SHORT", 2)
+                 .Case("LONG", 4)
+                 .Case("QUAD", 8)
+                 .Default(-1);
+  if (Size == -1)
+    return nullptr;
+
+  return make<BytesDataCommand>(readParenExpr(), Size);
+}
+
+StringRef ScriptParser::readParenLiteral() {
+  expect("(");
+  StringRef Tok = next();
+  expect(")");
+  return Tok;
+}
+
+OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd,
+                                          StringRef Location) {
+  if (Cmd->Location.empty() && Script->ErrorOnMissingSection)
+    error(Location + ": undefined section " + Cmd->Name);
+  if (Cmd->Sec)
+    return Cmd->Sec;
+  static OutputSection Dummy("", 0, 0);
+  return &Dummy;
+}
+
+Expr ScriptParser::readPrimary() {
+  if (peek() == "(")
+    return readParenExpr();
+
+  if (consume("~")) {
+    Expr E = readPrimary();
+    return [=] { return ~E().getValue(); };
+  }
+  if (consume("-")) {
+    Expr E = readPrimary();
+    return [=] { return -E().getValue(); };
+  }
+
+  StringRef Tok = next();
+  std::string Location = getCurrentLocation();
+
+  // Built-in functions are parsed here.
+  // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
+  if (Tok == "ABSOLUTE") {
+    Expr Inner = readParenExpr();
+    return [=] {
+      ExprValue I = Inner();
+      I.ForceAbsolute = true;
+      return I;
+    };
+  }
+  if (Tok == "ADDR") {
+    StringRef Name = readParenLiteral();
+    OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+    return [=]() -> ExprValue {
+      return {checkSection(Cmd, Location), 0, Location};
+    };
+  }
+  if (Tok == "ALIGN") {
+    expect("(");
+    Expr E = readExpr();
+    if (consume(")"))
+      return [=] { return alignTo(Script->getDot(), E().getValue()); };
+    expect(",");
+    Expr E2 = readExpr();
+    expect(")");
+    return [=] {
+      ExprValue V = E();
+      V.Alignment = E2().getValue();
+      return V;
+    };
+  }
+  if (Tok == "ALIGNOF") {
+    StringRef Name = readParenLiteral();
+    OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+    return [=] { return checkSection(Cmd, Location)->Alignment; };
+  }
+  if (Tok == "ASSERT")
+    return readAssertExpr();
+  if (Tok == "CONSTANT") {
+    StringRef Name = readParenLiteral();
+    return [=] { return getConstant(Name); };
+  }
+  if (Tok == "DATA_SEGMENT_ALIGN") {
+    expect("(");
+    Expr E = readExpr();
+    expect(",");
+    readExpr();
+    expect(")");
+    return [=] { return alignTo(Script->getDot(), E().getValue()); };
+  }
+  if (Tok == "DATA_SEGMENT_END") {
+    expect("(");
+    expect(".");
+    expect(")");
+    return [] { return Script->getDot(); };
+  }
+  if (Tok == "DATA_SEGMENT_RELRO_END") {
+    // GNU linkers implements more complicated logic to handle
+    // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and
+    // just align to the next page boundary for simplicity.
+    expect("(");
+    readExpr();
+    expect(",");
+    readExpr();
+    expect(")");
+    return [] { return alignTo(Script->getDot(), Target->PageSize); };
+  }
+  if (Tok == "DEFINED") {
+    StringRef Name = readParenLiteral();
+    return [=] { return Script->isDefined(Name) ? 1 : 0; };
+  }
+  if (Tok == "LENGTH") {
+    StringRef Name = readParenLiteral();
+    if (Script->Opt.MemoryRegions.count(Name) == 0)
+      setError("memory region not defined: " + Name);
+    return [=] { return Script->Opt.MemoryRegions[Name].Length; };
+  }
+  if (Tok == "LOADADDR") {
+    StringRef Name = readParenLiteral();
+    OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+    return [=] { return checkSection(Cmd, Location)->getLMA(); };
+  }
+  if (Tok == "ORIGIN") {
+    StringRef Name = readParenLiteral();
+    if (Script->Opt.MemoryRegions.count(Name) == 0)
+      setError("memory region not defined: " + Name);
+    return [=] { return Script->Opt.MemoryRegions[Name].Origin; };
+  }
+  if (Tok == "SEGMENT_START") {
+    expect("(");
+    skip();
+    expect(",");
+    Expr E = readExpr();
+    expect(")");
+    return [=] { return E(); };
+  }
+  if (Tok == "SIZEOF") {
+    StringRef Name = readParenLiteral();
+    OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+    // Linker script does not create an output section if its content is empty.
+    // We want to allow SIZEOF(.foo) where .foo is a section which happened to
+    // be empty.
+    return [=] { return Cmd->Sec ? Cmd->Sec->Size : 0; };
+  }
+  if (Tok == "SIZEOF_HEADERS")
+    return [=] { return elf::getHeaderSize(); };
+
+  // Tok is the dot.
+  if (Tok == ".")
+    return [=] { return Script->getSymbolValue(Location, Tok); };
+
+  // Tok is a literal number.
+  if (Optional<uint64_t> Val = parseInt(Tok))
+    return [=] { return *Val; };
+
+  // Tok is a symbol name.
+  if (!isValidCIdentifier(Tok))
+    setError("malformed number: " + Tok);
+  Script->Opt.ReferencedSymbols.push_back(Tok);
+  return [=] { return Script->getSymbolValue(Location, Tok); };
+}
+
+Expr ScriptParser::readTernary(Expr Cond) {
+  Expr L = readExpr();
+  expect(":");
+  Expr R = readExpr();
+  return [=] { return Cond().getValue() ? L() : R(); };
+}
+
+Expr ScriptParser::readParenExpr() {
+  expect("(");
+  Expr E = readExpr();
+  expect(")");
+  return E;
+}
+
+std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() {
+  std::vector<StringRef> Phdrs;
+  while (!Error && peek().startswith(":")) {
+    StringRef Tok = next();
+    Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1));
+  }
+  return Phdrs;
+}
+
+// Read a program header type name. The next token must be a
+// name of a program header type or a constant (e.g. "0x3").
+unsigned ScriptParser::readPhdrType() {
+  StringRef Tok = next();
+  if (Optional<uint64_t> Val = parseInt(Tok))
+    return *Val;
+
+  unsigned Ret = StringSwitch<unsigned>(Tok)
+                     .Case("PT_NULL", PT_NULL)
+                     .Case("PT_LOAD", PT_LOAD)
+                     .Case("PT_DYNAMIC", PT_DYNAMIC)
+                     .Case("PT_INTERP", PT_INTERP)
+                     .Case("PT_NOTE", PT_NOTE)
+                     .Case("PT_SHLIB", PT_SHLIB)
+                     .Case("PT_PHDR", PT_PHDR)
+                     .Case("PT_TLS", PT_TLS)
+                     .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
+                     .Case("PT_GNU_STACK", PT_GNU_STACK)
+                     .Case("PT_GNU_RELRO", PT_GNU_RELRO)
+                     .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
+                     .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
+                     .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
+                     .Default(-1);
+
+  if (Ret == (unsigned)-1) {
+    setError("invalid program header type: " + Tok);
+    return PT_NULL;
+  }
+  return Ret;
+}
+
+// Reads an anonymous version declaration.
+void ScriptParser::readAnonymousDeclaration() {
+  std::vector<SymbolVersion> Locals;
+  std::vector<SymbolVersion> Globals;
+  std::tie(Locals, Globals) = readSymbols();
+
+  for (SymbolVersion V : Locals) {
+    if (V.Name == "*")
+      Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+    else
+      Config->VersionScriptLocals.push_back(V);
+  }
+
+  for (SymbolVersion V : Globals)
+    Config->VersionScriptGlobals.push_back(V);
+
+  expect(";");
+}
+
+// Reads a non-anonymous version definition,
+// e.g. "VerStr { global: foo; bar; local: *; };".
+void ScriptParser::readVersionDeclaration(StringRef VerStr) {
+  // Read a symbol list.
+  std::vector<SymbolVersion> Locals;
+  std::vector<SymbolVersion> Globals;
+  std::tie(Locals, Globals) = readSymbols();
+
+  for (SymbolVersion V : Locals) {
+    if (V.Name == "*")
+      Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+    else
+      Config->VersionScriptLocals.push_back(V);
+  }
+
+  // Create a new version definition and add that to the global symbols.
+  VersionDefinition Ver;
+  Ver.Name = VerStr;
+  Ver.Globals = Globals;
+
+  // User-defined version number starts from 2 because 0 and 1 are
+  // reserved for VER_NDX_LOCAL and VER_NDX_GLOBAL, respectively.
+  Ver.Id = Config->VersionDefinitions.size() + 2;
+  Config->VersionDefinitions.push_back(Ver);
+
+  // Each version may have a parent version. For example, "Ver2"
+  // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1"
+  // as a parent. This version hierarchy is, probably against your
+  // instinct, purely for hint; the runtime doesn't care about it
+  // at all. In LLD, we simply ignore it.
+  if (peek() != ";")
+    skip();
+  expect(";");
+}
+
+static bool hasWildcard(StringRef S) {
+  return S.find_first_of("?*[") != StringRef::npos;
+}
+
+// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
+std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>>
+ScriptParser::readSymbols() {
+  std::vector<SymbolVersion> Locals;
+  std::vector<SymbolVersion> Globals;
+  std::vector<SymbolVersion> *V = &Globals;
+
+  while (!Error) {
+    if (consume("}"))
+      break;
+    if (consumeLabel("local")) {
+      V = &Locals;
+      continue;
+    }
+    if (consumeLabel("global")) {
+      V = &Globals;
+      continue;
+    }
+
+    if (consume("extern")) {
+      std::vector<SymbolVersion> Ext = readVersionExtern();
+      V->insert(V->end(), Ext.begin(), Ext.end());
+    } else {
+      StringRef Tok = next();
+      V->push_back({unquote(Tok), false, hasWildcard(Tok)});
+    }
+    expect(";");
+  }
+  return {Locals, Globals};
+}
+
+// Reads an "extern C++" directive, e.g.,
+// "extern "C++" { ns::*; "f(int, double)"; };"
+std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
+  StringRef Tok = next();
+  bool IsCXX = Tok == "\"C++\"";
+  if (!IsCXX && Tok != "\"C\"")
+    setError("Unknown language");
+  expect("{");
+
+  std::vector<SymbolVersion> Ret;
+  while (!Error && peek() != "}") {
+    StringRef Tok = next();
+    bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
+    Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
+    expect(";");
+  }
+
+  expect("}");
+  return Ret;
+}
+
+uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2,
+                                            StringRef S3) {
+  if (!consume(S1) && !consume(S2) && !consume(S3)) {
+    setError("expected one of: " + S1 + ", " + S2 + ", or " + S3);
+    return 0;
+  }
+  expect("=");
+  return readExpr()().getValue();
+}
+
+// Parse the MEMORY command as specified in:
+// https://sourceware.org/binutils/docs/ld/MEMORY.html
+//
+// MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... }
+void ScriptParser::readMemory() {
+  expect("{");
+  while (!Error && !consume("}")) {
+    StringRef Name = next();
+
+    uint32_t Flags = 0;
+    uint32_t NegFlags = 0;
+    if (consume("(")) {
+      std::tie(Flags, NegFlags) = readMemoryAttributes();
+      expect(")");
+    }
+    expect(":");
+
+    uint64_t Origin = readMemoryAssignment("ORIGIN", "org", "o");
+    expect(",");
+    uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
+
+    // Add the memory region to the region map (if it doesn't already exist).
+    auto It = Script->Opt.MemoryRegions.find(Name);
+    if (It != Script->Opt.MemoryRegions.end())
+      setError("region '" + Name + "' already defined");
+    else
+      Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags};
+  }
+}
+
+// This function parses the attributes used to match against section
+// flags when placing output sections in a memory region. These flags
+// are only used when an explicit memory region name is not used.
+std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() {
+  uint32_t Flags = 0;
+  uint32_t NegFlags = 0;
+  bool Invert = false;
+
+  for (char C : next().lower()) {
+    uint32_t Flag = 0;
+    if (C == '!')
+      Invert = !Invert;
+    else if (C == 'w')
+      Flag = SHF_WRITE;
+    else if (C == 'x')
+      Flag = SHF_EXECINSTR;
+    else if (C == 'a')
+      Flag = SHF_ALLOC;
+    else if (C != 'r')
+      setError("invalid memory region attribute");
+
+    if (Invert)
+      NegFlags |= Flag;
+    else
+      Flags |= Flag;
+  }
+  return {Flags, NegFlags};
+}
+
+void elf::readLinkerScript(MemoryBufferRef MB) {
+  ScriptParser(MB).readLinkerScript();
+}
+
+void elf::readVersionScript(MemoryBufferRef MB) {
+  ScriptParser(MB).readVersionScript();
+}
+
+void elf::readDynamicList(MemoryBufferRef MB) {
+  ScriptParser(MB).readDynamicList();
+}
diff --git a/ELF/ScriptParser.h b/ELF/ScriptParser.h
new file mode 100644 (file)
index 0000000..02f3a2b
--- /dev/null
@@ -0,0 +1,31 @@
+//===- ScriptParser.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_PARSER_H
+#define LLD_ELF_SCRIPT_PARSER_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lld {
+namespace elf {
+
+// Parses a linker script. Calling this function updates
+// Config and ScriptConfig.
+void readLinkerScript(MemoryBufferRef MB);
+
+// Parses a version script.
+void readVersionScript(MemoryBufferRef MB);
+
+void readDynamicList(MemoryBufferRef MB);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp
new file mode 100644 (file)
index 0000000..bca8638
--- /dev/null
@@ -0,0 +1,85 @@
+//===- Strings.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Strings.h"
+#include "Config.h"
+#include "Error.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Demangle/Demangle.h"
+#include <algorithm>
+#include <cstring>
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
+  for (StringRef S : Pat) {
+    Expected<GlobPattern> Pat = GlobPattern::create(S);
+    if (!Pat)
+      error(toString(Pat.takeError()));
+    else
+      Patterns.push_back(*Pat);
+  }
+}
+
+bool StringMatcher::match(StringRef S) const {
+  for (const GlobPattern &Pat : Patterns)
+    if (Pat.match(S))
+      return true;
+  return false;
+}
+
+// Converts a hex string (e.g. "deadbeef") to a vector.
+std::vector<uint8_t> elf::parseHex(StringRef S) {
+  std::vector<uint8_t> Hex;
+  while (!S.empty()) {
+    StringRef B = S.substr(0, 2);
+    S = S.substr(2);
+    uint8_t H;
+    if (!to_integer(B, H, 16)) {
+      error("not a hexadecimal value: " + B);
+      return {};
+    }
+    Hex.push_back(H);
+  }
+  return Hex;
+}
+
+static bool isAlpha(char C) {
+  return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
+}
+
+static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }
+
+// Returns true if S is valid as a C language identifier.
+bool elf::isValidCIdentifier(StringRef S) {
+  return !S.empty() && isAlpha(S[0]) &&
+         std::all_of(S.begin() + 1, S.end(), isAlnum);
+}
+
+// Returns the demangled C++ symbol name for Name.
+Optional<std::string> elf::demangle(StringRef Name) {
+  // itaniumDemangle can be used to demangle strings other than symbol
+  // names which do not necessarily start with "_Z". Name can be
+  // either a C or C++ symbol. Don't call itaniumDemangle if the name
+  // does not look like a C++ symbol name to avoid getting unexpected
+  // result for a C symbol that happens to match a mangled type name.
+  if (!Name.startswith("_Z"))
+    return None;
+
+  char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+  if (!Buf)
+    return None;
+  std::string S(Buf);
+  free(Buf);
+  return S;
+}
diff --git a/ELF/Strings.h b/ELF/Strings.h
new file mode 100644 (file)
index 0000000..68ccafa
--- /dev/null
@@ -0,0 +1,79 @@
+//===- Strings.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_STRINGS_H
+#define LLD_ELF_STRINGS_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/GlobPattern.h"
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+std::vector<uint8_t> parseHex(StringRef S);
+bool isValidCIdentifier(StringRef S);
+
+// This is a lazy version of StringRef. String size is computed lazily
+// when it is needed. It is more efficient than StringRef to instantiate
+// if you have a string whose size is unknown.
+//
+// ELF string tables contain a lot of null-terminated strings.
+// Most of them are not necessary for the linker because they are names
+// of local symbols and the linker doesn't use local symbol names for
+// name resolution. So, we use this class to represents strings read
+// from string tables.
+class StringRefZ {
+public:
+  StringRefZ() : Start(nullptr), Size(0) {}
+  StringRefZ(const char *S, size_t Size) : Start(S), Size(Size) {}
+
+  /*implicit*/ StringRefZ(const char *S) : Start(S), Size(-1) {}
+
+  /*implicit*/ StringRefZ(llvm::StringRef S)
+      : Start(S.data()), Size(S.size()) {}
+
+  operator llvm::StringRef() const {
+    if (Size == (size_t)-1)
+      Size = strlen(Start);
+    return {Start, Size};
+  }
+
+private:
+  const char *Start;
+  mutable size_t Size;
+};
+
+// This class represents multiple glob patterns.
+class StringMatcher {
+public:
+  StringMatcher() = default;
+  explicit StringMatcher(ArrayRef<StringRef> Pat);
+
+  bool match(StringRef S) const;
+
+private:
+  std::vector<llvm::GlobPattern> Patterns;
+};
+
+// Returns a demangled C++ symbol name. If Name is not a mangled
+// name, it returns Optional::None.
+llvm::Optional<std::string> demangle(StringRef Name);
+
+inline ArrayRef<uint8_t> toArrayRef(StringRef S) {
+  return {(const uint8_t *)S.data(), S.size()};
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
new file mode 100644 (file)
index 0000000..0c93240
--- /dev/null
@@ -0,0 +1,782 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Symbol table is a bag of all known symbols. We put all symbols of
+// all input files to the symbol table. The symbol table is basically
+// a hash table with the logic to resolve symbol name conflicts using
+// the symbol types.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolTable.h"
+#include "Config.h"
+#include "Error.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// All input object files must be for the same architecture
+// (e.g. it does not make sense to link x86 object files with
+// MIPS object files.) This function checks for that error.
+template <class ELFT> static bool isCompatible(InputFile *F) {
+  if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F))
+    return true;
+
+  if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) {
+    if (Config->EMachine != EM_MIPS)
+      return true;
+    if (isMipsN32Abi(F) == Config->MipsN32Abi)
+      return true;
+  }
+
+  if (!Config->Emulation.empty())
+    error(toString(F) + " is incompatible with " + Config->Emulation);
+  else
+    error(toString(F) + " is incompatible with " + toString(Config->FirstElf));
+  return false;
+}
+
+// Add symbols in File to the symbol table.
+template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
+  if (!Config->FirstElf && isa<ELFFileBase<ELFT>>(File))
+    Config->FirstElf = File;
+
+  if (!isCompatible<ELFT>(File))
+    return;
+
+  // Binary file
+  if (auto *F = dyn_cast<BinaryFile>(File)) {
+    BinaryFiles.push_back(F);
+    F->parse<ELFT>();
+    return;
+  }
+
+  // .a file
+  if (auto *F = dyn_cast<ArchiveFile>(File)) {
+    F->parse<ELFT>();
+    return;
+  }
+
+  // Lazy object file
+  if (auto *F = dyn_cast<LazyObjectFile>(File)) {
+    F->parse<ELFT>();
+    return;
+  }
+
+  if (Config->Trace)
+    message(toString(File));
+
+  // .so file
+  if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
+    // DSOs are uniquified not by filename but by soname.
+    F->parseSoName();
+    if (ErrorCount || !SoNames.insert(F->SoName).second)
+      return;
+    SharedFiles.push_back(F);
+    F->parseRest();
+    return;
+  }
+
+  // LLVM bitcode file
+  if (auto *F = dyn_cast<BitcodeFile>(File)) {
+    BitcodeFiles.push_back(F);
+    F->parse<ELFT>(ComdatGroups);
+    return;
+  }
+
+  // Regular object file
+  auto *F = cast<ObjectFile<ELFT>>(File);
+  ObjectFiles.push_back(F);
+  F->parse(ComdatGroups);
+}
+
+// This function is where all the optimizations of link-time
+// optimization happens. When LTO is in use, some input files are
+// not in native object file format but in the LLVM bitcode format.
+// This function compiles bitcode files into a few big native files
+// using LLVM functions and replaces bitcode symbols with the results.
+// Because all bitcode files that consist of a program are passed
+// to the compiler at once, it can do whole-program optimization.
+template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
+  if (BitcodeFiles.empty())
+    return;
+
+  // Compile bitcode files and replace bitcode symbols.
+  LTO.reset(new BitcodeCompiler);
+  for (BitcodeFile *F : BitcodeFiles)
+    LTO->add(*F);
+
+  for (InputFile *File : LTO->compile()) {
+    ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
+    DenseSet<CachedHashStringRef> DummyGroups;
+    Obj->parse(DummyGroups);
+    ObjectFiles.push_back(Obj);
+  }
+}
+
+template <class ELFT>
+DefinedRegular *SymbolTable<ELFT>::addAbsolute(StringRef Name,
+                                               uint8_t Visibility,
+                                               uint8_t Binding) {
+  Symbol *Sym =
+      addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
+  return cast<DefinedRegular>(Sym->body());
+}
+
+// Add Name as an "ignored" symbol. An ignored symbol is a regular
+// linker-synthesized defined symbol, but is only defined if needed.
+template <class ELFT>
+DefinedRegular *SymbolTable<ELFT>::addIgnored(StringRef Name,
+                                              uint8_t Visibility) {
+  SymbolBody *S = find(Name);
+  if (!S || S->isInCurrentDSO())
+    return nullptr;
+  return addAbsolute(Name, Visibility);
+}
+
+// Set a flag for --trace-symbol so that we can print out a log message
+// if a new symbol with the same name is inserted into the symbol table.
+template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) {
+  Symtab.insert({CachedHashStringRef(Name), {-1, true}});
+}
+
+// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
+// Used to implement --wrap.
+template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) {
+  SymbolBody *B = find(Name);
+  if (!B)
+    return;
+  Symbol *Sym = B->symbol();
+  Symbol *Real = addUndefined(Saver.save("__real_" + Name));
+  Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
+
+  // Tell LTO not to eliminate this symbol
+  Wrap->IsUsedInRegularObj = true;
+
+  Config->RenamedSymbols[Real] = {Sym, Real->Binding};
+  Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding};
+}
+
+// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
+template <class ELFT>
+void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, StringRef Name) {
+  SymbolBody *B = find(Name);
+  if (!B) {
+    error("-defsym: undefined symbol: " + Name);
+    return;
+  }
+  Symbol *Sym = B->symbol();
+  Symbol *AliasSym = addUndefined(Alias);
+
+  // Tell LTO not to eliminate this symbol
+  Sym->IsUsedInRegularObj = true;
+  Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding};
+}
+
+// Apply symbol renames created by -wrap and -defsym. The renames are created
+// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform
+// LTO (if LTO is running) not to include these symbols in IPO. Now that the
+// symbols are finalized, we can perform the replacement.
+template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() {
+  for (auto &KV : Config->RenamedSymbols) {
+    Symbol *Dst = KV.first;
+    Symbol *Src = KV.second.Target;
+    Dst->body()->copy(Src->body());
+    Dst->Binding = KV.second.OriginalBinding;
+  }
+}
+
+static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
+  if (VA == STV_DEFAULT)
+    return VB;
+  if (VB == STV_DEFAULT)
+    return VA;
+  return std::min(VA, VB);
+}
+
+// Find an existing symbol or create and insert a new one.
+template <class ELFT>
+std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
+  // <name>@@<version> means the symbol is the default version. In that
+  // case <name>@@<version> will be used to resolve references to <name>.
+  size_t Pos = Name.find("@@");
+  if (Pos != StringRef::npos)
+    Name = Name.take_front(Pos);
+
+  auto P = Symtab.insert(
+      {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)});
+  SymIndex &V = P.first->second;
+  bool IsNew = P.second;
+
+  if (V.Idx == -1) {
+    IsNew = true;
+    V = SymIndex((int)SymVector.size(), true);
+  }
+
+  Symbol *Sym;
+  if (IsNew) {
+    Sym = make<Symbol>();
+    Sym->InVersionScript = false;
+    Sym->Binding = STB_WEAK;
+    Sym->Visibility = STV_DEFAULT;
+    Sym->IsUsedInRegularObj = false;
+    Sym->ExportDynamic = false;
+    Sym->Traced = V.Traced;
+    Sym->VersionId = Config->DefaultSymbolVersion;
+    SymVector.push_back(Sym);
+  } else {
+    Sym = SymVector[V.Idx];
+  }
+  return {Sym, IsNew};
+}
+
+// Find an existing symbol or create and insert a new one, then apply the given
+// attributes.
+template <class ELFT>
+std::pair<Symbol *, bool>
+SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
+                          bool CanOmitFromDynSym, InputFile *File) {
+  bool IsUsedInRegularObj = !File || File->kind() == InputFile::ObjectKind;
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+
+  // Merge in the new symbol's visibility.
+  S->Visibility = getMinVisibility(S->Visibility, Visibility);
+
+  if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
+    S->ExportDynamic = true;
+
+  if (IsUsedInRegularObj)
+    S->IsUsedInRegularObj = true;
+
+  if (!WasInserted && S->body()->Type != SymbolBody::UnknownType &&
+      ((Type == STT_TLS) != S->body()->isTls())) {
+    error("TLS attribute mismatch: " + toString(*S->body()) +
+          "\n>>> defined in " + toString(S->body()->File) +
+          "\n>>> defined in " + toString(File));
+  }
+
+  return {S, WasInserted};
+}
+
+template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) {
+  return addUndefined(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT,
+                      /*Type*/ 0,
+                      /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
+}
+
+static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
+                                        uint8_t Binding, uint8_t StOther,
+                                        uint8_t Type, bool CanOmitFromDynSym,
+                                        InputFile *File) {
+  Symbol *S;
+  bool WasInserted;
+  uint8_t Visibility = getVisibility(StOther);
+  std::tie(S, WasInserted) =
+      insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+  // An undefined symbol with non default visibility must be satisfied
+  // in the same DSO.
+  if (WasInserted ||
+      (isa<SharedSymbol>(S->body()) && Visibility != STV_DEFAULT)) {
+    S->Binding = Binding;
+    replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
+    return S;
+  }
+  if (Binding != STB_WEAK) {
+    SymbolBody *B = S->body();
+    if (B->isShared() || B->isLazy() || B->isUndefined())
+      S->Binding = Binding;
+    if (auto *SS = dyn_cast<SharedSymbol>(B))
+      cast<SharedFile<ELFT>>(SS->File)->IsUsed = true;
+  }
+  if (auto *L = dyn_cast<Lazy>(S->body())) {
+    // An undefined weak will not fetch archive members, but we have to remember
+    // its type. See also comment in addLazyArchive.
+    if (S->isWeak())
+      L->Type = Type;
+    else if (InputFile *F = L->fetch())
+      addFile(F);
+  }
+  return S;
+}
+
+// Using .symver foo,foo@@VER unfortunately creates two symbols: foo and
+// foo@@VER. We want to effectively ignore foo, so give precedence to
+// foo@@VER.
+// FIXME: If users can transition to using
+// .symver foo,foo@@@VER
+// we can delete this hack.
+static int compareVersion(Symbol *S, StringRef Name) {
+  if (Name.find("@@") != StringRef::npos &&
+      S->body()->getName().find("@@") == StringRef::npos)
+    return 1;
+  if (Name.find("@@") == StringRef::npos &&
+      S->body()->getName().find("@@") != StringRef::npos)
+    return -1;
+  return 0;
+}
+
+// We have a new defined symbol with the specified binding. Return 1 if the new
+// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
+// strong defined symbols.
+static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding,
+                          StringRef Name) {
+  if (WasInserted)
+    return 1;
+  SymbolBody *Body = S->body();
+  if (!Body->isInCurrentDSO())
+    return 1;
+
+  if (int R = compareVersion(S, Name))
+    return R;
+
+  if (Binding == STB_WEAK)
+    return -1;
+  if (S->isWeak())
+    return 1;
+  return 0;
+}
+
+// We have a new non-common defined symbol with the specified binding. Return 1
+// if the new symbol should win, -1 if the new symbol should lose, or 0 if there
+// is a conflict. If the new symbol wins, also update the binding.
+template <typename ELFT>
+static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
+                                   bool IsAbsolute, typename ELFT::uint Value,
+                                   StringRef Name) {
+  if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) {
+    if (Cmp > 0)
+      S->Binding = Binding;
+    return Cmp;
+  }
+  SymbolBody *B = S->body();
+  if (isa<DefinedCommon>(B)) {
+    // Non-common symbols take precedence over common symbols.
+    if (Config->WarnCommon)
+      warn("common " + S->body()->getName() + " is overridden");
+    return 1;
+  } else if (auto *R = dyn_cast<DefinedRegular>(B)) {
+    if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
+        R->Value == Value)
+      return -1;
+  }
+  return 0;
+}
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
+                                     uint32_t Alignment, uint8_t Binding,
+                                     uint8_t StOther, uint8_t Type,
+                                     InputFile *File) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
+                                    /*CanOmitFromDynSym*/ false, File);
+  int Cmp = compareDefined(S, WasInserted, Binding, N);
+  if (Cmp > 0) {
+    S->Binding = Binding;
+    replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
+  } else if (Cmp == 0) {
+    auto *C = dyn_cast<DefinedCommon>(S->body());
+    if (!C) {
+      // Non-common symbols take precedence over common symbols.
+      if (Config->WarnCommon)
+        warn("common " + S->body()->getName() + " is overridden");
+      return S;
+    }
+
+    if (Config->WarnCommon)
+      warn("multiple common of " + S->body()->getName());
+
+    Alignment = C->Alignment = std::max(C->Alignment, Alignment);
+    if (Size > C->Size)
+      replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
+  }
+  return S;
+}
+
+static void warnOrError(const Twine &Msg) {
+  if (Config->AllowMultipleDefinition)
+    warn(Msg);
+  else
+    error(Msg);
+}
+
+static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) {
+  warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+              toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
+}
+
+template <class ELFT>
+static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec,
+                            typename ELFT::uint ErrOffset) {
+  DefinedRegular *D = dyn_cast<DefinedRegular>(Sym);
+  if (!D || !D->Section || !ErrSec) {
+    reportDuplicate(Sym, ErrSec ? ErrSec->getFile<ELFT>() : nullptr);
+    return;
+  }
+
+  // Construct and print an error message in the form of:
+  //
+  //   ld.lld: error: duplicate symbol: foo
+  //   >>> defined at bar.c:30
+  //   >>>            bar.o (/home/alice/src/bar.o)
+  //   >>> defined at baz.c:563
+  //   >>>            baz.o in archive libbaz.a
+  auto *Sec1 = cast<InputSectionBase>(D->Section);
+  std::string Src1 = Sec1->getSrcMsg<ELFT>(D->Value);
+  std::string Obj1 = Sec1->getObjMsg<ELFT>(D->Value);
+  std::string Src2 = ErrSec->getSrcMsg<ELFT>(ErrOffset);
+  std::string Obj2 = ErrSec->getObjMsg<ELFT>(ErrOffset);
+
+  std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at ";
+  if (!Src1.empty())
+    Msg += Src1 + "\n>>>            ";
+  Msg += Obj1 + "\n>>> defined at ";
+  if (!Src2.empty())
+    Msg += Src2 + "\n>>>            ";
+  Msg += Obj2;
+  warnOrError(Msg);
+}
+
+template <typename ELFT>
+Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther,
+                                      uint8_t Type, uint64_t Value,
+                                      uint64_t Size, uint8_t Binding,
+                                      SectionBase *Section, InputFile *File) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
+                                    /*CanOmitFromDynSym*/ false, File);
+  int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
+                                          Section == nullptr, Value, Name);
+  if (Cmp > 0)
+    replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type,
+                                Value, Size, Section, File);
+  else if (Cmp == 0)
+    reportDuplicate<ELFT>(S->body(),
+                          dyn_cast_or_null<InputSectionBase>(Section), Value);
+  return S;
+}
+
+template <typename ELFT>
+void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name,
+                                  const Elf_Sym &Sym,
+                                  const typename ELFT::Verdef *Verdef) {
+  // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
+  // as the visibility, which will leave the visibility in the symbol table
+  // unchanged.
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
+                                    /*CanOmitFromDynSym*/ true, File);
+  // Make sure we preempt DSO symbols with default visibility.
+  if (Sym.getVisibility() == STV_DEFAULT)
+    S->ExportDynamic = true;
+
+  SymbolBody *Body = S->body();
+  // An undefined symbol with non default visibility must be satisfied
+  // in the same DSO.
+  if (WasInserted ||
+      (isa<Undefined>(Body) && Body->getVisibility() == STV_DEFAULT)) {
+    replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(), &Sym,
+                              Verdef);
+    if (!S->isWeak())
+      File->IsUsed = true;
+  }
+}
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding,
+                                      uint8_t StOther, uint8_t Type,
+                                      bool CanOmitFromDynSym, BitcodeFile *F) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) =
+      insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F);
+  int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
+                                          /*IsAbs*/ false, /*Value*/ 0, Name);
+  if (Cmp > 0)
+    replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0,
+                                nullptr, F);
+  else if (Cmp == 0)
+    reportDuplicate(S->body(), F);
+  return S;
+}
+
+template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
+  auto It = Symtab.find(CachedHashStringRef(Name));
+  if (It == Symtab.end())
+    return nullptr;
+  SymIndex V = It->second;
+  if (V.Idx == -1)
+    return nullptr;
+  return SymVector[V.Idx]->body();
+}
+
+template <class ELFT>
+SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) {
+  if (SymbolBody *S = find(Name))
+    if (S->isInCurrentDSO())
+      return S;
+  return nullptr;
+}
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
+                                          const object::Archive::Symbol Sym) {
+  Symbol *S;
+  bool WasInserted;
+  StringRef Name = Sym.getName();
+  std::tie(S, WasInserted) = insert(Name);
+  if (WasInserted) {
+    replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
+    return S;
+  }
+  if (!S->body()->isUndefined())
+    return S;
+
+  // Weak undefined symbols should not fetch members from archives. If we were
+  // to keep old symbol we would not know that an archive member was available
+  // if a strong undefined symbol shows up afterwards in the link. If a strong
+  // undefined symbol never shows up, this lazy symbol will get to the end of
+  // the link and must be treated as the weak undefined one. We already marked
+  // this symbol as used when we added it to the symbol table, but we also need
+  // to preserve its type. FIXME: Move the Type field to Symbol.
+  if (S->isWeak()) {
+    replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
+    return S;
+  }
+  std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
+  if (!MBInfo.first.getBuffer().empty())
+    addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
+  return S;
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  if (WasInserted) {
+    replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType);
+    return;
+  }
+  if (!S->body()->isUndefined())
+    return;
+
+  // See comment for addLazyArchive above.
+  if (S->isWeak())
+    replaceBody<LazyObject>(S, Name, Obj, S->body()->Type);
+  else if (InputFile *F = Obj.fetch())
+    addFile(F);
+}
+
+// Process undefined (-u) flags by loading lazy symbols named by those flags.
+template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
+  for (StringRef S : Config->Undefined)
+    if (auto *L = dyn_cast_or_null<Lazy>(find(S)))
+      if (InputFile *File = L->fetch())
+        addFile(File);
+}
+
+// This function takes care of the case in which shared libraries depend on
+// the user program (not the other way, which is usual). Shared libraries
+// may have undefined symbols, expecting that the user program provides
+// the definitions for them. An example is BSD's __progname symbol.
+// We need to put such symbols to the main program's .dynsym so that
+// shared libraries can find them.
+// Except this, we ignore undefined symbols in DSOs.
+template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
+  for (SharedFile<ELFT> *File : SharedFiles) {
+    for (StringRef U : File->getUndefinedSymbols()) {
+      SymbolBody *Sym = find(U);
+      if (!Sym || !Sym->isDefined())
+        continue;
+      Sym->symbol()->ExportDynamic = true;
+
+      // If -dynamic-list is given, the default version is set to
+      // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym.
+      // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were
+      // specified by -dynamic-list.
+      Sym->symbol()->VersionId = VER_NDX_GLOBAL;
+    }
+  }
+}
+
+// Initialize DemangledSyms with a map from demangled symbols to symbol
+// objects. Used to handle "extern C++" directive in version scripts.
+//
+// The map will contain all demangled symbols. That can be very large,
+// and in LLD we generally want to avoid do anything for each symbol.
+// Then, why are we doing this? Here's why.
+//
+// Users can use "extern C++ {}" directive to match against demangled
+// C++ symbols. For example, you can write a pattern such as
+// "llvm::*::foo(int, ?)". Obviously, there's no way to handle this
+// other than trying to match a pattern against all demangled symbols.
+// So, if "extern C++" feature is used, we need to demangle all known
+// symbols.
+template <class ELFT>
+StringMap<std::vector<SymbolBody *>> &SymbolTable<ELFT>::getDemangledSyms() {
+  if (!DemangledSyms) {
+    DemangledSyms.emplace();
+    for (Symbol *Sym : SymVector) {
+      SymbolBody *B = Sym->body();
+      if (B->isUndefined())
+        continue;
+      if (Optional<std::string> S = demangle(B->getName()))
+        (*DemangledSyms)[*S].push_back(B);
+      else
+        (*DemangledSyms)[B->getName()].push_back(B);
+    }
+  }
+  return *DemangledSyms;
+}
+
+template <class ELFT>
+std::vector<SymbolBody *> SymbolTable<ELFT>::findByVersion(SymbolVersion Ver) {
+  if (Ver.IsExternCpp)
+    return getDemangledSyms().lookup(Ver.Name);
+  if (SymbolBody *B = find(Ver.Name))
+    if (!B->isUndefined())
+      return {B};
+  return {};
+}
+
+template <class ELFT>
+std::vector<SymbolBody *>
+SymbolTable<ELFT>::findAllByVersion(SymbolVersion Ver) {
+  std::vector<SymbolBody *> Res;
+  StringMatcher M(Ver.Name);
+
+  if (Ver.IsExternCpp) {
+    for (auto &P : getDemangledSyms())
+      if (M.match(P.first()))
+        Res.insert(Res.end(), P.second.begin(), P.second.end());
+    return Res;
+  }
+
+  for (Symbol *Sym : SymVector) {
+    SymbolBody *B = Sym->body();
+    if (!B->isUndefined() && M.match(B->getName()))
+      Res.push_back(B);
+  }
+  return Res;
+}
+
+// If there's only one anonymous version definition in a version
+// script file, the script does not actually define any symbol version,
+// but just specifies symbols visibilities.
+template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() {
+  for (SymbolVersion &Ver : Config->VersionScriptGlobals)
+    assignExactVersion(Ver, VER_NDX_GLOBAL, "global");
+  for (SymbolVersion &Ver : Config->VersionScriptGlobals)
+    assignWildcardVersion(Ver, VER_NDX_GLOBAL);
+  for (SymbolVersion &Ver : Config->VersionScriptLocals)
+    assignExactVersion(Ver, VER_NDX_LOCAL, "local");
+  for (SymbolVersion &Ver : Config->VersionScriptLocals)
+    assignWildcardVersion(Ver, VER_NDX_LOCAL);
+}
+
+// Set symbol versions to symbols. This function handles patterns
+// containing no wildcard characters.
+template <class ELFT>
+void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver,
+                                           uint16_t VersionId,
+                                           StringRef VersionName) {
+  if (Ver.HasWildcard)
+    return;
+
+  // Get a list of symbols which we need to assign the version to.
+  std::vector<SymbolBody *> Syms = findByVersion(Ver);
+  if (Syms.empty()) {
+    if (Config->NoUndefinedVersion)
+      error("version script assignment of '" + VersionName + "' to symbol '" +
+            Ver.Name + "' failed: symbol not defined");
+    return;
+  }
+
+  // Assign the version.
+  for (SymbolBody *B : Syms) {
+    // Skip symbols containing version info because symbol versions
+    // specified by symbol names take precedence over version scripts.
+    // See parseSymbolVersion().
+    if (B->getName().find('@') != StringRef::npos)
+      continue;
+
+    Symbol *Sym = B->symbol();
+    if (Sym->InVersionScript)
+      warn("duplicate symbol '" + Ver.Name + "' in version script");
+    Sym->VersionId = VersionId;
+    Sym->InVersionScript = true;
+  }
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
+                                              uint16_t VersionId) {
+  if (!Ver.HasWildcard)
+    return;
+
+  // Exact matching takes precendence over fuzzy matching,
+  // so we set a version to a symbol only if no version has been assigned
+  // to the symbol. This behavior is compatible with GNU.
+  for (SymbolBody *B : findAllByVersion(Ver))
+    if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
+      B->symbol()->VersionId = VersionId;
+}
+
+// This function processes version scripts by updating VersionId
+// member of symbols.
+template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
+  // Handle edge cases first.
+  handleAnonymousVersion();
+
+  // Now we have version definitions, so we need to set version ids to symbols.
+  // Each version definition has a glob pattern, and all symbols that match
+  // with the pattern get that version.
+
+  // First, we assign versions to exact matching symbols,
+  // i.e. version definitions not containing any glob meta-characters.
+  for (VersionDefinition &V : Config->VersionDefinitions)
+    for (SymbolVersion &Ver : V.Globals)
+      assignExactVersion(Ver, V.Id, V.Name);
+
+  // Next, we assign versions to fuzzy matching symbols,
+  // i.e. version definitions containing glob meta-characters.
+  // Note that because the last match takes precedence over previous matches,
+  // we iterate over the definitions in the reverse order.
+  for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
+    for (SymbolVersion &Ver : V.Globals)
+      assignWildcardVersion(Ver, V.Id);
+
+  // Symbol themselves might know their versions because symbols
+  // can contain versions in the form of <name>@<version>.
+  // Let them parse and update their names to exclude version suffix.
+  for (Symbol *Sym : SymVector)
+    Sym->body()->parseSymbolVersion();
+}
+
+template class elf::SymbolTable<ELF32LE>;
+template class elf::SymbolTable<ELF32BE>;
+template class elf::SymbolTable<ELF64LE>;
+template class elf::SymbolTable<ELF64BE>;
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
new file mode 100644 (file)
index 0000000..4ba101f
--- /dev/null
@@ -0,0 +1,147 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYMBOL_TABLE_H
+#define LLD_ELF_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "LTO.h"
+#include "Strings.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace elf {
+
+struct Symbol;
+
+// SymbolTable is a bucket of all known symbols, including defined,
+// undefined, or lazy symbols (the last one is symbols in archive
+// files whose archive members are not yet loaded).
+//
+// We put all symbols of all files to a SymbolTable, and the
+// SymbolTable selects the "best" symbols if there are name
+// conflicts. For example, obviously, a defined symbol is better than
+// an undefined symbol. Or, if there's a conflict between a lazy and a
+// undefined, it'll read an archive member to read a real definition
+// to replace the lazy symbol. The logic is implemented in the
+// add*() functions, which are called by input files as they are parsed. There
+// is one add* function per symbol type.
+template <class ELFT> class SymbolTable {
+  typedef typename ELFT::Sym Elf_Sym;
+
+public:
+  void addFile(InputFile *File);
+  void addCombinedLTOObject();
+  void addSymbolAlias(StringRef Alias, StringRef Name);
+  void addSymbolWrap(StringRef Name);
+  void applySymbolRenames();
+
+  ArrayRef<Symbol *> getSymbols() const { return SymVector; }
+  ArrayRef<ObjectFile<ELFT> *> getObjectFiles() const { return ObjectFiles; }
+  ArrayRef<BinaryFile *> getBinaryFiles() const { return BinaryFiles; }
+  ArrayRef<SharedFile<ELFT> *> getSharedFiles() const { return SharedFiles; }
+
+  DefinedRegular *addAbsolute(StringRef Name,
+                              uint8_t Visibility = llvm::ELF::STV_HIDDEN,
+                              uint8_t Binding = llvm::ELF::STB_GLOBAL);
+  DefinedRegular *addIgnored(StringRef Name,
+                             uint8_t Visibility = llvm::ELF::STV_HIDDEN);
+
+  Symbol *addUndefined(StringRef Name);
+  Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding,
+                       uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym,
+                       InputFile *File);
+
+  Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
+                     uint64_t Value, uint64_t Size, uint8_t Binding,
+                     SectionBase *Section, InputFile *File);
+
+  void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
+                 const typename ELFT::Verdef *Verdef);
+
+  Symbol *addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
+  void addLazyObject(StringRef Name, LazyObjectFile &Obj);
+  Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
+                     uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
+
+  Symbol *addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
+                    uint8_t Binding, uint8_t StOther, uint8_t Type,
+                    InputFile *File);
+
+  std::pair<Symbol *, bool> insert(StringRef Name);
+  std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
+                                   uint8_t Visibility, bool CanOmitFromDynSym,
+                                   InputFile *File);
+
+  void scanUndefinedFlags();
+  void scanShlibUndefined();
+  void scanVersionScript();
+
+  SymbolBody *find(StringRef Name);
+  SymbolBody *findInCurrentDSO(StringRef Name);
+
+  void trace(StringRef Name);
+
+private:
+  std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
+  std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver);
+
+  llvm::StringMap<std::vector<SymbolBody *>> &getDemangledSyms();
+  void handleAnonymousVersion();
+  void assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+                          StringRef VersionName);
+  void assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId);
+
+  struct SymIndex {
+    SymIndex(int Idx, bool Traced) : Idx(Idx), Traced(Traced) {}
+    int Idx : 31;
+    unsigned Traced : 1;
+  };
+
+  // The order the global symbols are in is not defined. We can use an arbitrary
+  // order, but it has to be reproducible. That is true even when cross linking.
+  // The default hashing of StringRef produces different results on 32 and 64
+  // bit systems so we use a map to a vector. That is arbitrary, deterministic
+  // but a bit inefficient.
+  // FIXME: Experiment with passing in a custom hashing or sorting the symbols
+  // once symbol resolution is finished.
+  llvm::DenseMap<llvm::CachedHashStringRef, SymIndex> Symtab;
+  std::vector<Symbol *> SymVector;
+
+  // Comdat groups define "link once" sections. If two comdat groups have the
+  // same name, only one of them is linked, and the other is ignored. This set
+  // is used to uniquify them.
+  llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
+
+  std::vector<ObjectFile<ELFT> *> ObjectFiles;
+  std::vector<SharedFile<ELFT> *> SharedFiles;
+  std::vector<BitcodeFile *> BitcodeFiles;
+  std::vector<BinaryFile *> BinaryFiles;
+
+  // Set of .so files to not link the same shared object file more than once.
+  llvm::DenseSet<StringRef> SoNames;
+
+  // A map from demangled symbol names to their symbol objects.
+  // This mapping is 1:N because two symbols with different versions
+  // can have the same name. We use this map to handle "extern C++ {}"
+  // directive in version scripts.
+  llvm::Optional<llvm::StringMap<std::vector<SymbolBody *>>> DemangledSyms;
+
+  // For LTO.
+  std::unique_ptr<BitcodeCompiler> LTO;
+};
+
+template <class ELFT> struct Symtab { static SymbolTable<ELFT> *X; };
+template <class ELFT> SymbolTable<ELFT> *Symtab<ELFT>::X;
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
new file mode 100644 (file)
index 0000000..c69007e
--- /dev/null
@@ -0,0 +1,399 @@
+//===- Symbols.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Writer.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Path.h"
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+DefinedRegular *ElfSym::Bss;
+DefinedRegular *ElfSym::Etext1;
+DefinedRegular *ElfSym::Etext2;
+DefinedRegular *ElfSym::Edata1;
+DefinedRegular *ElfSym::Edata2;
+DefinedRegular *ElfSym::End1;
+DefinedRegular *ElfSym::End2;
+DefinedRegular *ElfSym::GlobalOffsetTable;
+DefinedRegular *ElfSym::MipsGp;
+DefinedRegular *ElfSym::MipsGpDisp;
+DefinedRegular *ElfSym::MipsLocalGp;
+
+static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
+  switch (Body.kind()) {
+  case SymbolBody::DefinedRegularKind: {
+    auto &D = cast<DefinedRegular>(Body);
+    SectionBase *IS = D.Section;
+    if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS))
+      IS = ISB->Repl;
+
+    // According to the ELF spec reference to a local symbol from outside
+    // the group are not allowed. Unfortunately .eh_frame breaks that rule
+    // and must be treated specially. For now we just replace the symbol with
+    // 0.
+    if (IS == &InputSection::Discarded)
+      return 0;
+
+    // This is an absolute symbol.
+    if (!IS)
+      return D.Value;
+
+    uint64_t Offset = D.Value;
+
+    // An object in an SHF_MERGE section might be referenced via a
+    // section symbol (as a hack for reducing the number of local
+    // symbols).
+    // Depending on the addend, the reference via a section symbol
+    // refers to a different object in the merge section.
+    // Since the objects in the merge section are not necessarily
+    // contiguous in the output, the addend can thus affect the final
+    // VA in a non-linear way.
+    // To make this work, we incorporate the addend into the section
+    // offset (and zero out the addend for later processing) so that
+    // we find the right object in the section.
+    if (D.isSection()) {
+      Offset += Addend;
+      Addend = 0;
+    }
+
+    const OutputSection *OutSec = IS->getOutputSection();
+
+    // In the typical case, this is actually very simple and boils
+    // down to adding together 3 numbers:
+    // 1. The address of the output section.
+    // 2. The offset of the input section within the output section.
+    // 3. The offset within the input section (this addition happens
+    //    inside InputSection::getOffset).
+    //
+    // If you understand the data structures involved with this next
+    // line (and how they get built), then you have a pretty good
+    // understanding of the linker.
+    uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
+
+    if (D.isTls() && !Config->Relocatable) {
+      if (!Out::TlsPhdr)
+        fatal(toString(D.File) +
+              " has an STT_TLS symbol but doesn't have an SHF_TLS section");
+      return VA - Out::TlsPhdr->p_vaddr;
+    }
+    return VA;
+  }
+  case SymbolBody::DefinedCommonKind:
+    if (!Config->DefineCommon)
+      return 0;
+    return InX::Common->getParent()->Addr + InX::Common->OutSecOff +
+           cast<DefinedCommon>(Body).Offset;
+  case SymbolBody::SharedKind: {
+    auto &SS = cast<SharedSymbol>(Body);
+    if (SS.NeedsCopy)
+      return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff +
+             SS.CopyRelSecOff;
+    if (SS.NeedsPltAddr)
+      return Body.getPltVA();
+    return 0;
+  }
+  case SymbolBody::UndefinedKind:
+    return 0;
+  case SymbolBody::LazyArchiveKind:
+  case SymbolBody::LazyObjectKind:
+    assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
+    return 0;
+  }
+  llvm_unreachable("invalid symbol kind");
+}
+
+SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
+                       uint8_t Type)
+    : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal),
+      IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
+      IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
+
+// Returns true if a symbol can be replaced at load-time by a symbol
+// with the same name defined in other ELF executable or DSO.
+bool SymbolBody::isPreemptible() const {
+  if (isLocal())
+    return false;
+
+  // Shared symbols resolve to the definition in the DSO. The exceptions are
+  // symbols with copy relocations (which resolve to .bss) or preempt plt
+  // entries (which resolve to that plt entry).
+  if (isShared())
+    return !NeedsCopy && !NeedsPltAddr;
+
+  // That's all that can be preempted in a non-DSO.
+  if (!Config->Shared)
+    return false;
+
+  // Only symbols that appear in dynsym can be preempted.
+  if (!symbol()->includeInDynsym())
+    return false;
+
+  // Only default visibility symbols can be preempted.
+  if (symbol()->Visibility != STV_DEFAULT)
+    return false;
+
+  // -Bsymbolic means that definitions are not preempted.
+  if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
+    return !isDefined();
+  return true;
+}
+
+// Overwrites all attributes with Other's so that this symbol becomes
+// an alias to Other. This is useful for handling some options such as
+// --wrap.
+void SymbolBody::copy(SymbolBody *Other) {
+  memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer,
+         sizeof(Symbol::Body));
+}
+
+uint64_t SymbolBody::getVA(int64_t Addend) const {
+  uint64_t OutVA = getSymVA(*this, Addend);
+  return OutVA + Addend;
+}
+
+uint64_t SymbolBody::getGotVA() const {
+  return InX::Got->getVA() + getGotOffset();
+}
+
+uint64_t SymbolBody::getGotOffset() const {
+  return GotIndex * Target->GotEntrySize;
+}
+
+uint64_t SymbolBody::getGotPltVA() const {
+  if (this->IsInIgot)
+    return InX::IgotPlt->getVA() + getGotPltOffset();
+  return InX::GotPlt->getVA() + getGotPltOffset();
+}
+
+uint64_t SymbolBody::getGotPltOffset() const {
+  return GotPltIndex * Target->GotPltEntrySize;
+}
+
+uint64_t SymbolBody::getPltVA() const {
+  if (this->IsInIplt)
+    return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
+  return InX::Plt->getVA() + Target->PltHeaderSize +
+         PltIndex * Target->PltEntrySize;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
+  if (const auto *C = dyn_cast<DefinedCommon>(this))
+    return C->Size;
+  if (const auto *DR = dyn_cast<DefinedRegular>(this))
+    return DR->Size;
+  if (const auto *S = dyn_cast<SharedSymbol>(this))
+    return S->getSize<ELFT>();
+  return 0;
+}
+
+OutputSection *SymbolBody::getOutputSection() const {
+  if (auto *S = dyn_cast<DefinedRegular>(this)) {
+    if (S->Section)
+      return S->Section->getOutputSection();
+    return nullptr;
+  }
+
+  if (auto *S = dyn_cast<SharedSymbol>(this)) {
+    if (S->NeedsCopy)
+      return S->CopyRelSec->getParent();
+    return nullptr;
+  }
+
+  if (isa<DefinedCommon>(this)) {
+    if (Config->DefineCommon)
+      return InX::Common->getParent();
+    return nullptr;
+  }
+
+  return nullptr;
+}
+
+// If a symbol name contains '@', the characters after that is
+// a symbol version name. This function parses that.
+void SymbolBody::parseSymbolVersion() {
+  StringRef S = getName();
+  size_t Pos = S.find('@');
+  if (Pos == 0 || Pos == StringRef::npos)
+    return;
+  StringRef Verstr = S.substr(Pos + 1);
+  if (Verstr.empty())
+    return;
+
+  // Truncate the symbol name so that it doesn't include the version string.
+  Name = {S.data(), Pos};
+
+  // If this is not in this DSO, it is not a definition.
+  if (!isInCurrentDSO())
+    return;
+
+  // '@@' in a symbol name means the default version.
+  // It is usually the most recent one.
+  bool IsDefault = (Verstr[0] == '@');
+  if (IsDefault)
+    Verstr = Verstr.substr(1);
+
+  for (VersionDefinition &Ver : Config->VersionDefinitions) {
+    if (Ver.Name != Verstr)
+      continue;
+
+    if (IsDefault)
+      symbol()->VersionId = Ver.Id;
+    else
+      symbol()->VersionId = Ver.Id | VERSYM_HIDDEN;
+    return;
+  }
+
+  // It is an error if the specified version is not defined.
+  // Usually version script is not provided when linking executable,
+  // but we may still want to override a versioned symbol from DSO,
+  // so we do not report error in this case.
+  if (Config->Shared)
+    error(toString(File) + ": symbol " + S + " has undefined version " +
+          Verstr);
+}
+
+Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
+                 uint8_t Type)
+    : SymbolBody(K, Name, IsLocal, StOther, Type) {}
+
+template <class ELFT> bool DefinedRegular::isMipsPIC() const {
+  typedef typename ELFT::Ehdr Elf_Ehdr;
+  if (!Section || !isFunc())
+    return false;
+
+  auto *Sec = cast<InputSectionBase>(Section);
+  const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
+  return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
+         (Hdr->e_flags & EF_MIPS_PIC);
+}
+
+Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
+                     uint8_t Type, InputFile *File)
+    : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
+  this->File = File;
+}
+
+DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
+                             uint8_t StOther, uint8_t Type, InputFile *File)
+    : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
+              Type),
+      Alignment(Alignment), Size(Size) {
+  this->File = File;
+}
+
+// If a shared symbol is referred via a copy relocation, its alignment
+// becomes part of the ABI. This function returns a symbol alignment.
+// Because symbols don't have alignment attributes, we need to infer that.
+template <class ELFT> uint32_t SharedSymbol::getAlignment() const {
+  auto *File = cast<SharedFile<ELFT>>(this->File);
+  uint32_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign;
+  uint64_t SymValue = getSym<ELFT>().st_value;
+  uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue);
+  return std::min(SecAlign, SymAlign);
+}
+
+InputFile *Lazy::fetch() {
+  if (auto *S = dyn_cast<LazyArchive>(this))
+    return S->fetch();
+  return cast<LazyObject>(this)->fetch();
+}
+
+LazyArchive::LazyArchive(ArchiveFile &File,
+                         const llvm::object::Archive::Symbol S, uint8_t Type)
+    : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) {
+  this->File = &File;
+}
+
+LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
+    : Lazy(LazyObjectKind, Name, Type) {
+  this->File = &File;
+}
+
+InputFile *LazyArchive::fetch() {
+  std::pair<MemoryBufferRef, uint64_t> MBInfo = file()->getMember(&Sym);
+
+  // getMember returns an empty buffer if the member was already
+  // read from the library.
+  if (MBInfo.first.getBuffer().empty())
+    return nullptr;
+  return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second);
+}
+
+InputFile *LazyObject::fetch() { return file()->fetch(); }
+
+uint8_t Symbol::computeBinding() const {
+  if (Config->Relocatable)
+    return Binding;
+  if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+    return STB_LOCAL;
+  if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO())
+    return STB_LOCAL;
+  if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
+    return STB_GLOBAL;
+  return Binding;
+}
+
+bool Symbol::includeInDynsym() const {
+  if (computeBinding() == STB_LOCAL)
+    return false;
+  return ExportDynamic || body()->isShared() ||
+         (body()->isUndefined() && Config->Shared);
+}
+
+// Print out a log message for --trace-symbol.
+void elf::printTraceSymbol(Symbol *Sym) {
+  SymbolBody *B = Sym->body();
+  std::string S;
+  if (B->isUndefined())
+    S = ": reference to ";
+  else if (B->isCommon())
+    S = ": common definition of ";
+  else
+    S = ": definition of ";
+
+  message(toString(B->File) + S + B->getName());
+}
+
+// Returns a symbol for an error message.
+std::string lld::toString(const SymbolBody &B) {
+  if (Config->Demangle)
+    if (Optional<std::string> S = demangle(B.getName()))
+      return *S;
+  return B.getName();
+}
+
+template uint32_t SymbolBody::template getSize<ELF32LE>() const;
+template uint32_t SymbolBody::template getSize<ELF32BE>() const;
+template uint64_t SymbolBody::template getSize<ELF64LE>() const;
+template uint64_t SymbolBody::template getSize<ELF64BE>() const;
+
+template bool DefinedRegular::template isMipsPIC<ELF32LE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF32BE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF64LE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF64BE>() const;
+
+template uint32_t SharedSymbol::template getAlignment<ELF32LE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF32BE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF64LE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF64BE>() const;
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
new file mode 100644 (file)
index 0000000..a1b3a6f
--- /dev/null
@@ -0,0 +1,414 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// All symbols are handled as SymbolBodies regardless of their types.
+// This file defines various types of SymbolBodies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYMBOLS_H
+#define LLD_ELF_SYMBOLS_H
+
+#include "InputSection.h"
+#include "Strings.h"
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+
+class ArchiveFile;
+class BitcodeFile;
+class InputFile;
+class LazyObjectFile;
+template <class ELFT> class ObjectFile;
+class OutputSection;
+template <class ELFT> class SharedFile;
+
+struct Symbol;
+
+// The base class for real symbol classes.
+class SymbolBody {
+public:
+  enum Kind {
+    DefinedFirst,
+    DefinedRegularKind = DefinedFirst,
+    SharedKind,
+    DefinedCommonKind,
+    DefinedLast = DefinedCommonKind,
+    UndefinedKind,
+    LazyArchiveKind,
+    LazyObjectKind,
+  };
+
+  SymbolBody(Kind K) : SymbolKind(K) {}
+
+  Symbol *symbol();
+  const Symbol *symbol() const {
+    return const_cast<SymbolBody *>(this)->symbol();
+  }
+
+  Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+  bool isUndefined() const { return SymbolKind == UndefinedKind; }
+  bool isDefined() const { return SymbolKind <= DefinedLast; }
+  bool isCommon() const { return SymbolKind == DefinedCommonKind; }
+  bool isLazy() const {
+    return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
+  }
+  bool isShared() const { return SymbolKind == SharedKind; }
+  bool isInCurrentDSO() const {
+    return !isUndefined() && !isShared() && !isLazy();
+  }
+  bool isLocal() const { return IsLocal; }
+  bool isPreemptible() const;
+  StringRef getName() const { return Name; }
+  uint8_t getVisibility() const { return StOther & 0x3; }
+  void parseSymbolVersion();
+  void copy(SymbolBody *Other);
+
+  bool isInGot() const { return GotIndex != -1U; }
+  bool isInPlt() const { return PltIndex != -1U; }
+
+  uint64_t getVA(int64_t Addend = 0) const;
+
+  uint64_t getGotOffset() const;
+  uint64_t getGotVA() const;
+  uint64_t getGotPltOffset() const;
+  uint64_t getGotPltVA() const;
+  uint64_t getPltVA() const;
+  template <class ELFT> typename ELFT::uint getSize() const;
+  OutputSection *getOutputSection() const;
+
+  // The file from which this symbol was created.
+  InputFile *File = nullptr;
+
+  uint32_t DynsymIndex = 0;
+  uint32_t GotIndex = -1;
+  uint32_t GotPltIndex = -1;
+  uint32_t PltIndex = -1;
+  uint32_t GlobalDynIndex = -1;
+
+protected:
+  SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
+             uint8_t Type);
+
+  const unsigned SymbolKind : 8;
+
+public:
+  // True if the linker has to generate a copy relocation.
+  // For SharedSymbol only.
+  unsigned NeedsCopy : 1;
+
+  // True the symbol should point to its PLT entry.
+  // For SharedSymbol only.
+  unsigned NeedsPltAddr : 1;
+
+  // True if this is a local symbol.
+  unsigned IsLocal : 1;
+
+  // True if this symbol has an entry in the global part of MIPS GOT.
+  unsigned IsInGlobalMipsGot : 1;
+
+  // True if this symbol is referenced by 32-bit GOT relocations.
+  unsigned Is32BitMipsGot : 1;
+
+  // True if this symbol is in the Iplt sub-section of the Plt.
+  unsigned IsInIplt : 1;
+
+  // True if this symbol is in the Igot sub-section of the .got.plt or .got.
+  unsigned IsInIgot : 1;
+
+  // The following fields have the same meaning as the ELF symbol attributes.
+  uint8_t Type;    // symbol type
+  uint8_t StOther; // st_other field value
+
+  // The Type field may also have this value. It means that we have not yet seen
+  // a non-Lazy symbol with this name, so we don't know what its type is. The
+  // Type field is normally set to this value for Lazy symbols unless we saw a
+  // weak undefined symbol first, in which case we need to remember the original
+  // symbol's type in order to check for TLS mismatches.
+  enum { UnknownType = 255 };
+
+  bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
+  bool isTls() const { return Type == llvm::ELF::STT_TLS; }
+  bool isFunc() const { return Type == llvm::ELF::STT_FUNC; }
+  bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
+  bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
+  bool isFile() const { return Type == llvm::ELF::STT_FILE; }
+
+protected:
+  StringRefZ Name;
+};
+
+// The base class for any defined symbols.
+class Defined : public SymbolBody {
+public:
+  Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type);
+  static bool classof(const SymbolBody *S) { return S->isDefined(); }
+};
+
+class DefinedCommon : public Defined {
+public:
+  DefinedCommon(StringRef N, uint64_t Size, uint32_t Alignment, uint8_t StOther,
+                uint8_t Type, InputFile *File);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == SymbolBody::DefinedCommonKind;
+  }
+
+  // The output offset of this common symbol in the output bss. Computed by the
+  // writer.
+  uint64_t Offset;
+
+  // The maximum alignment we have seen for this symbol.
+  uint32_t Alignment;
+
+  uint64_t Size;
+};
+
+// Regular defined symbols read from object file symbol tables.
+class DefinedRegular : public Defined {
+public:
+  DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
+                 uint64_t Value, uint64_t Size, SectionBase *Section,
+                 InputFile *File)
+      : Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type),
+        Value(Value), Size(Size), Section(Section) {
+    this->File = File;
+  }
+
+  // Return true if the symbol is a PIC function.
+  template <class ELFT> bool isMipsPIC() const;
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == SymbolBody::DefinedRegularKind;
+  }
+
+  uint64_t Value;
+  uint64_t Size;
+  SectionBase *Section;
+};
+
+class Undefined : public SymbolBody {
+public:
+  Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
+            InputFile *F);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == UndefinedKind;
+  }
+};
+
+class SharedSymbol : public Defined {
+public:
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == SymbolBody::SharedKind;
+  }
+
+  SharedSymbol(InputFile *File, StringRef Name, uint8_t StOther, uint8_t Type,
+               const void *ElfSym, const void *Verdef)
+      : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, StOther, Type),
+        Verdef(Verdef), ElfSym(ElfSym) {
+    // IFuncs defined in DSOs are treated as functions by the static linker.
+    if (isGnuIFunc())
+      this->Type = llvm::ELF::STT_FUNC;
+    this->File = File;
+  }
+
+  template <class ELFT> uint64_t getShndx() const {
+    return getSym<ELFT>().st_shndx;
+  }
+
+  template <class ELFT> uint64_t getValue() const {
+    return getSym<ELFT>().st_value;
+  }
+
+  template <class ELFT> uint64_t getSize() const {
+    return getSym<ELFT>().st_size;
+  }
+
+  template <class ELFT> uint32_t getAlignment() const;
+
+  // This field is a pointer to the symbol's version definition.
+  const void *Verdef;
+
+  // CopyRelSec and CopyRelSecOff are significant only when NeedsCopy is true.
+  InputSection *CopyRelSec;
+  uint64_t CopyRelSecOff;
+
+private:
+  template <class ELFT> const typename ELFT::Sym &getSym() const {
+    return *(const typename ELFT::Sym *)ElfSym;
+  }
+
+  const void *ElfSym;
+};
+
+// This class represents a symbol defined in an archive file. It is
+// created from an archive file header, and it knows how to load an
+// object file from an archive to replace itself with a defined
+// symbol. If the resolver finds both Undefined and Lazy for
+// the same name, it will ask the Lazy to load a file.
+class Lazy : public SymbolBody {
+public:
+  static bool classof(const SymbolBody *S) { return S->isLazy(); }
+
+  // Returns an object file for this symbol, or a nullptr if the file
+  // was already returned.
+  InputFile *fetch();
+
+protected:
+  Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type)
+      : SymbolBody(K, Name, /*IsLocal=*/false, llvm::ELF::STV_DEFAULT, Type) {}
+};
+
+// LazyArchive symbols represents symbols in archive files.
+class LazyArchive : public Lazy {
+public:
+  LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S,
+              uint8_t Type);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == LazyArchiveKind;
+  }
+
+  ArchiveFile *file() { return (ArchiveFile *)this->File; }
+  InputFile *fetch();
+
+private:
+  const llvm::object::Archive::Symbol Sym;
+};
+
+// LazyObject symbols represents symbols in object files between
+// --start-lib and --end-lib options.
+class LazyObject : public Lazy {
+public:
+  LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == LazyObjectKind;
+  }
+
+  LazyObjectFile *file() { return (LazyObjectFile *)this->File; }
+  InputFile *fetch();
+};
+
+// Some linker-generated symbols need to be created as
+// DefinedRegular symbols.
+struct ElfSym {
+  // __bss_start
+  static DefinedRegular *Bss;
+
+  // etext and _etext
+  static DefinedRegular *Etext1;
+  static DefinedRegular *Etext2;
+
+  // edata and _edata
+  static DefinedRegular *Edata1;
+  static DefinedRegular *Edata2;
+
+  // end and _end
+  static DefinedRegular *End1;
+  static DefinedRegular *End2;
+
+  // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+  // be at some offset from the base of the .got section, usually 0 or
+  // the end of the .got.
+  static DefinedRegular *GlobalOffsetTable;
+
+  // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
+  static DefinedRegular *MipsGp;
+  static DefinedRegular *MipsGpDisp;
+  static DefinedRegular *MipsLocalGp;
+};
+
+// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
+// always one Symbol for each symbol name. The resolver updates the SymbolBody
+// stored in the Body field of this object as it resolves symbols. Symbol also
+// holds computed properties of symbol names.
+struct Symbol {
+  // Symbol binding. This is on the Symbol to track changes during resolution.
+  // In particular:
+  // An undefined weak is still weak when it resolves to a shared library.
+  // An undefined weak will not fetch archive members, but we have to remember
+  // it is weak.
+  uint8_t Binding;
+
+  // Version definition index.
+  uint16_t VersionId;
+
+  // Symbol visibility. This is the computed minimum visibility of all
+  // observed non-DSO symbols.
+  unsigned Visibility : 2;
+
+  // True if the symbol was used for linking and thus need to be added to the
+  // output file's symbol table. This is true for all symbols except for
+  // unreferenced DSO symbols and bitcode symbols that are unreferenced except
+  // by other bitcode objects.
+  unsigned IsUsedInRegularObj : 1;
+
+  // If this flag is true and the symbol has protected or default visibility, it
+  // will appear in .dynsym. This flag is set by interposable DSO symbols in
+  // executables, by most symbols in DSOs and executables built with
+  // --export-dynamic, and by dynamic lists.
+  unsigned ExportDynamic : 1;
+
+  // True if this symbol is specified by --trace-symbol option.
+  unsigned Traced : 1;
+
+  // This symbol version was found in a version script.
+  unsigned InVersionScript : 1;
+
+  bool includeInDynsym() const;
+  uint8_t computeBinding() const;
+  bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
+
+  // This field is used to store the Symbol's SymbolBody. This instantiation of
+  // AlignedCharArrayUnion gives us a struct with a char array field that is
+  // large and aligned enough to store any derived class of SymbolBody.
+  llvm::AlignedCharArrayUnion<DefinedCommon, DefinedRegular, Undefined,
+                              SharedSymbol, LazyArchive, LazyObject>
+      Body;
+
+  SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
+  const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); }
+};
+
+void printTraceSymbol(Symbol *Sym);
+
+template <typename T, typename... ArgT>
+void replaceBody(Symbol *S, ArgT &&... Arg) {
+  static_assert(sizeof(T) <= sizeof(S->Body), "Body too small");
+  static_assert(alignof(T) <= alignof(decltype(S->Body)),
+                "Body not aligned enough");
+  assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr &&
+         "Not a SymbolBody");
+
+  new (S->Body.buffer) T(std::forward<ArgT>(Arg)...);
+
+  // Print out a log message if --trace-symbol was specified.
+  // This is for debugging.
+  if (S->Traced)
+    printTraceSymbol(S);
+}
+
+inline Symbol *SymbolBody::symbol() {
+  assert(!isLocal());
+  return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) -
+                                    offsetof(Symbol, Body));
+}
+} // namespace elf
+
+std::string toString(const elf::SymbolBody &B);
+} // namespace lld
+
+#endif
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
new file mode 100644 (file)
index 0000000..4bbec4a
--- /dev/null
@@ -0,0 +1,2431 @@
+//===- SyntheticSections.cpp ----------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains linker-synthesized sections. Currently,
+// synthetic sections are created either output sections or input sections,
+// but we are rewriting code so that all synthetic sections are created as
+// input sections.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntheticSections.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Target.h"
+#include "Threads.h"
+#include "Writer.h"
+#include "lld/Config/Version.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Object/Decompressor.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/SHA1.h"
+#include "llvm/Support/xxhash.h"
+#include <cstdlib>
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+uint64_t SyntheticSection::getVA() const {
+  if (OutputSection *Sec = getParent())
+    return Sec->Addr + OutSecOff;
+  return 0;
+}
+
+template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() {
+  std::vector<DefinedCommon *> V;
+  for (Symbol *S : Symtab<ELFT>::X->getSymbols())
+    if (auto *B = dyn_cast<DefinedCommon>(S->body()))
+      V.push_back(B);
+  return V;
+}
+
+// Find all common symbols and allocate space for them.
+template <class ELFT> InputSection *elf::createCommonSection() {
+  if (!Config->DefineCommon)
+    return nullptr;
+
+  // Sort the common symbols by alignment as an heuristic to pack them better.
+  std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>();
+  if (Syms.empty())
+    return nullptr;
+
+  std::stable_sort(Syms.begin(), Syms.end(),
+                   [](const DefinedCommon *A, const DefinedCommon *B) {
+                     return A->Alignment > B->Alignment;
+                   });
+
+  BssSection *Sec = make<BssSection>("COMMON");
+  for (DefinedCommon *Sym : Syms)
+    Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment);
+  return Sec;
+}
+
+// Returns an LLD version string.
+static ArrayRef<uint8_t> getVersion() {
+  // Check LLD_VERSION first for ease of testing.
+  // You can get consitent output by using the environment variable.
+  // This is only for testing.
+  StringRef S = getenv("LLD_VERSION");
+  if (S.empty())
+    S = Saver.save(Twine("Linker: ") + getLLDVersion());
+
+  // +1 to include the terminating '\0'.
+  return {(const uint8_t *)S.data(), S.size() + 1};
+}
+
+// Creates a .comment section containing LLD version info.
+// With this feature, you can identify LLD-generated binaries easily
+// by "readelf --string-dump .comment <file>".
+// The returned object is a mergeable string section.
+template <class ELFT> MergeInputSection *elf::createCommentSection() {
+  typename ELFT::Shdr Hdr = {};
+  Hdr.sh_flags = SHF_MERGE | SHF_STRINGS;
+  Hdr.sh_type = SHT_PROGBITS;
+  Hdr.sh_entsize = 1;
+  Hdr.sh_addralign = 1;
+
+  auto *Ret =
+      make<MergeInputSection>((ObjectFile<ELFT> *)nullptr, &Hdr, ".comment");
+  Ret->Data = getVersion();
+  Ret->splitIntoPieces();
+  return Ret;
+}
+
+// .MIPS.abiflags section.
+template <class ELFT>
+MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags)
+    : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
+      Flags(Flags) {
+  this->Entsize = sizeof(Elf_Mips_ABIFlags);
+}
+
+template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) {
+  memcpy(Buf, &Flags, sizeof(Flags));
+}
+
+template <class ELFT>
+MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
+  Elf_Mips_ABIFlags Flags = {};
+  bool Create = false;
+
+  for (InputSectionBase *Sec : InputSections) {
+    if (Sec->Type != SHT_MIPS_ABIFLAGS)
+      continue;
+    Sec->Live = false;
+    Create = true;
+
+    std::string Filename = toString(Sec->getFile<ELFT>());
+    const size_t Size = Sec->Data.size();
+    // Older version of BFD (such as the default FreeBSD linker) concatenate
+    // .MIPS.abiflags instead of merging. To allow for this case (or potential
+    // zero padding) we ignore everything after the first Elf_Mips_ABIFlags
+    if (Size < sizeof(Elf_Mips_ABIFlags)) {
+      error(Filename + ": invalid size of .MIPS.abiflags section: got " +
+            Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags)));
+      return nullptr;
+    }
+    auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->Data.data());
+    if (S->version != 0) {
+      error(Filename + ": unexpected .MIPS.abiflags version " +
+            Twine(S->version));
+      return nullptr;
+    }
+
+    // LLD checks ISA compatibility in getMipsEFlags(). Here we just
+    // select the highest number of ISA/Rev/Ext.
+    Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
+    Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
+    Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext);
+    Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size);
+    Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size);
+    Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size);
+    Flags.ases |= S->ases;
+    Flags.flags1 |= S->flags1;
+    Flags.flags2 |= S->flags2;
+    Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename);
+  };
+
+  if (Create)
+    return make<MipsAbiFlagsSection<ELFT>>(Flags);
+  return nullptr;
+}
+
+// .MIPS.options section.
+template <class ELFT>
+MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo)
+    : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
+      Reginfo(Reginfo) {
+  this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf);
+  Options->kind = ODK_REGINFO;
+  Options->size = getSize();
+
+  if (!Config->Relocatable)
+    Reginfo.ri_gp_value = InX::MipsGot->getGp();
+  memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
+}
+
+template <class ELFT>
+MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
+  // N64 ABI only.
+  if (!ELFT::Is64Bits)
+    return nullptr;
+
+  Elf_Mips_RegInfo Reginfo = {};
+  bool Create = false;
+
+  for (InputSectionBase *Sec : InputSections) {
+    if (Sec->Type != SHT_MIPS_OPTIONS)
+      continue;
+    Sec->Live = false;
+    Create = true;
+
+    std::string Filename = toString(Sec->getFile<ELFT>());
+    ArrayRef<uint8_t> D = Sec->Data;
+
+    while (!D.empty()) {
+      if (D.size() < sizeof(Elf_Mips_Options)) {
+        error(Filename + ": invalid size of .MIPS.options section");
+        break;
+      }
+
+      auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
+      if (Opt->kind == ODK_REGINFO) {
+        if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
+          error(Filename + ": unsupported non-zero ri_gp_value");
+        Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
+        Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
+        break;
+      }
+
+      if (!Opt->size)
+        fatal(Filename + ": zero option descriptor size");
+      D = D.slice(Opt->size);
+    }
+  };
+
+  if (Create)
+    return make<MipsOptionsSection<ELFT>>(Reginfo);
+  return nullptr;
+}
+
+// MIPS .reginfo section.
+template <class ELFT>
+MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
+    : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
+      Reginfo(Reginfo) {
+  this->Entsize = sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
+  if (!Config->Relocatable)
+    Reginfo.ri_gp_value = InX::MipsGot->getGp();
+  memcpy(Buf, &Reginfo, sizeof(Reginfo));
+}
+
+template <class ELFT>
+MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
+  // Section should be alive for O32 and N32 ABIs only.
+  if (ELFT::Is64Bits)
+    return nullptr;
+
+  Elf_Mips_RegInfo Reginfo = {};
+  bool Create = false;
+
+  for (InputSectionBase *Sec : InputSections) {
+    if (Sec->Type != SHT_MIPS_REGINFO)
+      continue;
+    Sec->Live = false;
+    Create = true;
+
+    if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) {
+      error(toString(Sec->getFile<ELFT>()) +
+            ": invalid size of .reginfo section");
+      return nullptr;
+    }
+    auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
+    if (Config->Relocatable && R->ri_gp_value)
+      error(toString(Sec->getFile<ELFT>()) +
+            ": unsupported non-zero ri_gp_value");
+
+    Reginfo.ri_gprmask |= R->ri_gprmask;
+    Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
+  };
+
+  if (Create)
+    return make<MipsReginfoSection<ELFT>>(Reginfo);
+  return nullptr;
+}
+
+InputSection *elf::createInterpSection() {
+  // StringSaver guarantees that the returned string ends with '\0'.
+  StringRef S = Saver.save(Config->DynamicLinker);
+  ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1};
+
+  auto *Sec =
+      make<InputSection>(SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp");
+  Sec->Live = true;
+  return Sec;
+}
+
+SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+                                   uint64_t Size, InputSectionBase *Section) {
+  auto *S = make<DefinedRegular>(Name, /*IsLocal*/ true, STV_DEFAULT, Type,
+                                 Value, Size, Section, nullptr);
+  if (InX::SymTab)
+    InX::SymTab->addSymbol(S);
+  return S;
+}
+
+static size_t getHashSize() {
+  switch (Config->BuildId) {
+  case BuildIdKind::Fast:
+    return 8;
+  case BuildIdKind::Md5:
+  case BuildIdKind::Uuid:
+    return 16;
+  case BuildIdKind::Sha1:
+    return 20;
+  case BuildIdKind::Hexstring:
+    return Config->BuildIdVector.size();
+  default:
+    llvm_unreachable("unknown BuildIdKind");
+  }
+}
+
+BuildIdSection::BuildIdSection()
+    : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"),
+      HashSize(getHashSize()) {}
+
+void BuildIdSection::writeTo(uint8_t *Buf) {
+  endianness E = Config->Endianness;
+  write32(Buf, 4, E);                   // Name size
+  write32(Buf + 4, HashSize, E);        // Content size
+  write32(Buf + 8, NT_GNU_BUILD_ID, E); // Type
+  memcpy(Buf + 12, "GNU", 4);           // Name string
+  HashBuf = Buf + 16;
+}
+
+// Split one uint8 array into small pieces of uint8 arrays.
+static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr,
+                                            size_t ChunkSize) {
+  std::vector<ArrayRef<uint8_t>> Ret;
+  while (Arr.size() > ChunkSize) {
+    Ret.push_back(Arr.take_front(ChunkSize));
+    Arr = Arr.drop_front(ChunkSize);
+  }
+  if (!Arr.empty())
+    Ret.push_back(Arr);
+  return Ret;
+}
+
+// Computes a hash value of Data using a given hash function.
+// In order to utilize multiple cores, we first split data into 1MB
+// chunks, compute a hash for each chunk, and then compute a hash value
+// of the hash values.
+void BuildIdSection::computeHash(
+    llvm::ArrayRef<uint8_t> Data,
+    std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) {
+  std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024);
+  std::vector<uint8_t> Hashes(Chunks.size() * HashSize);
+
+  // Compute hash values.
+  parallelForEachN(0, Chunks.size(), [&](size_t I) {
+    HashFn(Hashes.data() + I * HashSize, Chunks[I]);
+  });
+
+  // Write to the final output buffer.
+  HashFn(HashBuf, Hashes);
+}
+
+BssSection::BssSection(StringRef Name)
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {}
+
+size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) {
+  if (OutputSection *Sec = getParent())
+    Sec->updateAlignment(Alignment);
+  this->Size = alignTo(this->Size, Alignment) + Size;
+  this->Alignment = std::max(this->Alignment, Alignment);
+  return this->Size - Size;
+}
+
+void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
+  switch (Config->BuildId) {
+  case BuildIdKind::Fast:
+    computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+      write64le(Dest, xxHash64(toStringRef(Arr)));
+    });
+    break;
+  case BuildIdKind::Md5:
+    computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+      memcpy(Dest, MD5::hash(Arr).data(), 16);
+    });
+    break;
+  case BuildIdKind::Sha1:
+    computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+      memcpy(Dest, SHA1::hash(Arr).data(), 20);
+    });
+    break;
+  case BuildIdKind::Uuid:
+    if (getRandomBytes(HashBuf, HashSize))
+      error("entropy source failure");
+    break;
+  case BuildIdKind::Hexstring:
+    memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size());
+    break;
+  default:
+    llvm_unreachable("unknown BuildIdKind");
+  }
+}
+
+template <class ELFT>
+EhFrameSection<ELFT>::EhFrameSection()
+    : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {}
+
+// Search for an existing CIE record or create a new one.
+// CIE records from input object files are uniquified by their contents
+// and where their relocations point to.
+template <class ELFT>
+template <class RelTy>
+CieRecord *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece,
+                                        ArrayRef<RelTy> Rels) {
+  auto *Sec = cast<EhInputSection>(Piece.ID);
+  const endianness E = ELFT::TargetEndianness;
+  if (read32<E>(Piece.data().data() + 4) != 0)
+    fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
+
+  SymbolBody *Personality = nullptr;
+  unsigned FirstRelI = Piece.FirstRelocation;
+  if (FirstRelI != (unsigned)-1)
+    Personality =
+        &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
+
+  // Search for an existing CIE by CIE contents/relocation target pair.
+  CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
+
+  // If not found, create a new one.
+  if (Cie->Piece == nullptr) {
+    Cie->Piece = &Piece;
+    Cies.push_back(Cie);
+  }
+  return Cie;
+}
+
+// There is one FDE per function. Returns true if a given FDE
+// points to a live function.
+template <class ELFT>
+template <class RelTy>
+bool EhFrameSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
+                                     ArrayRef<RelTy> Rels) {
+  auto *Sec = cast<EhInputSection>(Piece.ID);
+  unsigned FirstRelI = Piece.FirstRelocation;
+  if (FirstRelI == (unsigned)-1)
+    return false;
+  const RelTy &Rel = Rels[FirstRelI];
+  SymbolBody &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
+  auto *D = dyn_cast<DefinedRegular>(&B);
+  if (!D || !D->Section)
+    return false;
+  auto *Target =
+      cast<InputSectionBase>(cast<InputSectionBase>(D->Section)->Repl);
+  return Target && Target->Live;
+}
+
+// .eh_frame is a sequence of CIE or FDE records. In general, there
+// is one CIE record per input object file which is followed by
+// a list of FDEs. This function searches an existing CIE or create a new
+// one and associates FDEs to the CIE.
+template <class ELFT>
+template <class RelTy>
+void EhFrameSection<ELFT>::addSectionAux(EhInputSection *Sec,
+                                         ArrayRef<RelTy> Rels) {
+  const endianness E = ELFT::TargetEndianness;
+
+  DenseMap<size_t, CieRecord *> OffsetToCie;
+  for (EhSectionPiece &Piece : Sec->Pieces) {
+    // The empty record is the end marker.
+    if (Piece.size() == 4)
+      return;
+
+    size_t Offset = Piece.InputOff;
+    uint32_t ID = read32<E>(Piece.data().data() + 4);
+    if (ID == 0) {
+      OffsetToCie[Offset] = addCie(Piece, Rels);
+      continue;
+    }
+
+    uint32_t CieOffset = Offset + 4 - ID;
+    CieRecord *Cie = OffsetToCie[CieOffset];
+    if (!Cie)
+      fatal(toString(Sec) + ": invalid CIE reference");
+
+    if (!isFdeLive(Piece, Rels))
+      continue;
+    Cie->FdePieces.push_back(&Piece);
+    NumFdes++;
+  }
+}
+
+template <class ELFT>
+void EhFrameSection<ELFT>::addSection(InputSectionBase *C) {
+  auto *Sec = cast<EhInputSection>(C);
+  Sec->Parent = this;
+  updateAlignment(Sec->Alignment);
+  Sections.push_back(Sec);
+  for (auto *DS : Sec->DependentSections)
+    DependentSections.push_back(DS);
+
+  // .eh_frame is a sequence of CIE or FDE records. This function
+  // splits it into pieces so that we can call
+  // SplitInputSection::getSectionPiece on the section.
+  Sec->split<ELFT>();
+  if (Sec->Pieces.empty())
+    return;
+
+  if (Sec->NumRelocations) {
+    if (Sec->AreRelocsRela)
+      addSectionAux(Sec, Sec->template relas<ELFT>());
+    else
+      addSectionAux(Sec, Sec->template rels<ELFT>());
+    return;
+  }
+  addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
+}
+
+template <class ELFT>
+static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
+  memcpy(Buf, D.data(), D.size());
+
+  // Fix the size field. -4 since size does not include the size field itself.
+  const endianness E = ELFT::TargetEndianness;
+  write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
+}
+
+template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() {
+  if (this->Size)
+    return; // Already finalized.
+
+  size_t Off = 0;
+  for (CieRecord *Cie : Cies) {
+    Cie->Piece->OutputOff = Off;
+    Off += alignTo(Cie->Piece->size(), Config->Wordsize);
+
+    for (EhSectionPiece *Fde : Cie->FdePieces) {
+      Fde->OutputOff = Off;
+      Off += alignTo(Fde->size(), Config->Wordsize);
+    }
+  }
+
+  // The LSB standard does not allow a .eh_frame section with zero
+  // Call Frame Information records. Therefore add a CIE record length
+  // 0 as a terminator if this .eh_frame section is empty.
+  if (Off == 0)
+    Off = 4;
+
+  this->Size = Off;
+}
+
+template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
+  const endianness E = ELFT::TargetEndianness;
+  switch (Size) {
+  case DW_EH_PE_udata2:
+    return read16<E>(Buf);
+  case DW_EH_PE_udata4:
+    return read32<E>(Buf);
+  case DW_EH_PE_udata8:
+    return read64<E>(Buf);
+  case DW_EH_PE_absptr:
+    if (ELFT::Is64Bits)
+      return read64<E>(Buf);
+    return read32<E>(Buf);
+  }
+  fatal("unknown FDE size encoding");
+}
+
+// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
+// We need it to create .eh_frame_hdr section.
+template <class ELFT>
+uint64_t EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
+                                        uint8_t Enc) {
+  // The starting address to which this FDE applies is
+  // stored at FDE + 8 byte.
+  size_t Off = FdeOff + 8;
+  uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
+  if ((Enc & 0x70) == DW_EH_PE_absptr)
+    return Addr;
+  if ((Enc & 0x70) == DW_EH_PE_pcrel)
+    return Addr + getParent()->Addr + Off;
+  fatal("unknown FDE size relative encoding");
+}
+
+template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
+  const endianness E = ELFT::TargetEndianness;
+  for (CieRecord *Cie : Cies) {
+    size_t CieOffset = Cie->Piece->OutputOff;
+    writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
+
+    for (EhSectionPiece *Fde : Cie->FdePieces) {
+      size_t Off = Fde->OutputOff;
+      writeCieFde<ELFT>(Buf + Off, Fde->data());
+
+      // FDE's second word should have the offset to an associated CIE.
+      // Write it.
+      write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
+    }
+  }
+
+  for (EhInputSection *S : Sections)
+    S->relocateAlloc(Buf, nullptr);
+
+  // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
+  // to get a FDE from an address to which FDE is applied. So here
+  // we obtain two addresses and pass them to EhFrameHdr object.
+  if (In<ELFT>::EhFrameHdr) {
+    for (CieRecord *Cie : Cies) {
+      uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
+      for (SectionPiece *Fde : Cie->FdePieces) {
+        uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+        uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+        In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
+      }
+    }
+  }
+}
+
+GotSection::GotSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+                       Target->GotEntrySize, ".got") {}
+
+void GotSection::addEntry(SymbolBody &Sym) {
+  Sym.GotIndex = NumEntries;
+  ++NumEntries;
+}
+
+bool GotSection::addDynTlsEntry(SymbolBody &Sym) {
+  if (Sym.GlobalDynIndex != -1U)
+    return false;
+  Sym.GlobalDynIndex = NumEntries;
+  // Global Dynamic TLS entries take two GOT slots.
+  NumEntries += 2;
+  return true;
+}
+
+// Reserves TLS entries for a TLS module ID and a TLS block offset.
+// In total it takes two GOT slots.
+bool GotSection::addTlsIndex() {
+  if (TlsIndexOff != uint32_t(-1))
+    return false;
+  TlsIndexOff = NumEntries * Config->Wordsize;
+  NumEntries += 2;
+  return true;
+}
+
+uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const {
+  return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
+}
+
+uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const {
+  return B.GlobalDynIndex * Config->Wordsize;
+}
+
+void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; }
+
+bool GotSection::empty() const {
+  // If we have a relocation that is relative to GOT (such as GOTOFFREL),
+  // we need to emit a GOT even if it's empty.
+  return NumEntries == 0 && !HasGotOffRel;
+}
+
+void GotSection::writeTo(uint8_t *Buf) {
+  // Buf points to the start of this section's buffer,
+  // whereas InputSectionBase::relocateAlloc() expects its argument
+  // to point to the start of the output section.
+  relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
+}
+
+MipsGotSection::MipsGotSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
+                       ".got") {}
+
+void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) {
+  // For "true" local symbols which can be referenced from the same module
+  // only compiler creates two instructions for address loading:
+  //
+  // lw   $8, 0($gp) # R_MIPS_GOT16
+  // addi $8, $8, 0  # R_MIPS_LO16
+  //
+  // The first instruction loads high 16 bits of the symbol address while
+  // the second adds an offset. That allows to reduce number of required
+  // GOT entries because only one global offset table entry is necessary
+  // for every 64 KBytes of local data. So for local symbols we need to
+  // allocate number of GOT entries to hold all required "page" addresses.
+  //
+  // All global symbols (hidden and regular) considered by compiler uniformly.
+  // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
+  // to load address of the symbol. So for each such symbol we need to
+  // allocate dedicated GOT entry to store its address.
+  //
+  // If a symbol is preemptible we need help of dynamic linker to get its
+  // final address. The corresponding GOT entries are allocated in the
+  // "global" part of GOT. Entries for non preemptible global symbol allocated
+  // in the "local" part of GOT.
+  //
+  // See "Global Offset Table" in Chapter 5:
+  // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
+    // At this point we do not know final symbol value so to reduce number
+    // of allocated GOT entries do the following trick. Save all output
+    // sections referenced by GOT relocations. Then later in the `finalize`
+    // method calculate number of "pages" required to cover all saved output
+    // section and allocate appropriate number of GOT entries.
+    PageIndexMap.insert({Sym.getOutputSection(), 0});
+    return;
+  }
+  if (Sym.isTls()) {
+    // GOT entries created for MIPS TLS relocations behave like
+    // almost GOT entries from other ABIs. They go to the end
+    // of the global offset table.
+    Sym.GotIndex = TlsEntries.size();
+    TlsEntries.push_back(&Sym);
+    return;
+  }
+  auto AddEntry = [&](SymbolBody &S, uint64_t A, GotEntries &Items) {
+    if (S.isInGot() && !A)
+      return;
+    size_t NewIndex = Items.size();
+    if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second)
+      return;
+    Items.emplace_back(&S, A);
+    if (!A)
+      S.GotIndex = NewIndex;
+  };
+  if (Sym.isPreemptible()) {
+    // Ignore addends for preemptible symbols. They got single GOT entry anyway.
+    AddEntry(Sym, 0, GlobalEntries);
+    Sym.IsInGlobalMipsGot = true;
+  } else if (Expr == R_MIPS_GOT_OFF32) {
+    AddEntry(Sym, Addend, LocalEntries32);
+    Sym.Is32BitMipsGot = true;
+  } else {
+    // Hold local GOT entries accessed via a 16-bit index separately.
+    // That allows to write them in the beginning of the GOT and keep
+    // their indexes as less as possible to escape relocation's overflow.
+    AddEntry(Sym, Addend, LocalEntries);
+  }
+}
+
+bool MipsGotSection::addDynTlsEntry(SymbolBody &Sym) {
+  if (Sym.GlobalDynIndex != -1U)
+    return false;
+  Sym.GlobalDynIndex = TlsEntries.size();
+  // Global Dynamic TLS entries take two GOT slots.
+  TlsEntries.push_back(nullptr);
+  TlsEntries.push_back(&Sym);
+  return true;
+}
+
+// Reserves TLS entries for a TLS module ID and a TLS block offset.
+// In total it takes two GOT slots.
+bool MipsGotSection::addTlsIndex() {
+  if (TlsIndexOff != uint32_t(-1))
+    return false;
+  TlsIndexOff = TlsEntries.size() * Config->Wordsize;
+  TlsEntries.push_back(nullptr);
+  TlsEntries.push_back(nullptr);
+  return true;
+}
+
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+  return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+  return (Size + 0xfffe) / 0xffff + 1;
+}
+
+uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B,
+                                            int64_t Addend) const {
+  const OutputSection *OutSec = B.getOutputSection();
+  uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+  uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
+  uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
+  assert(Index < PageEntriesNum);
+  return (HeaderEntriesNum + Index) * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B,
+                                            int64_t Addend) const {
+  // Calculate offset of the GOT entries block: TLS, global, local.
+  uint64_t Index = HeaderEntriesNum + PageEntriesNum;
+  if (B.isTls())
+    Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
+  else if (B.IsInGlobalMipsGot)
+    Index += LocalEntries.size() + LocalEntries32.size();
+  else if (B.Is32BitMipsGot)
+    Index += LocalEntries.size();
+  // Calculate offset of the GOT entry in the block.
+  if (B.isInGot())
+    Index += B.GotIndex;
+  else {
+    auto It = EntryIndexMap.find({&B, Addend});
+    assert(It != EntryIndexMap.end());
+    Index += It->second;
+  }
+  return Index * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getTlsOffset() const {
+  return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const {
+  return B.GlobalDynIndex * Config->Wordsize;
+}
+
+const SymbolBody *MipsGotSection::getFirstGlobalEntry() const {
+  return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
+}
+
+unsigned MipsGotSection::getLocalEntriesNum() const {
+  return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
+         LocalEntries32.size();
+}
+
+void MipsGotSection::finalizeContents() { updateAllocSize(); }
+
+void MipsGotSection::updateAllocSize() {
+  PageEntriesNum = 0;
+  for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
+    // For each output section referenced by GOT page relocations calculate
+    // and save into PageIndexMap an upper bound of MIPS GOT entries required
+    // to store page addresses of local symbols. We assume the worst case -
+    // each 64kb page of the output section has at least one GOT relocation
+    // against it. And take in account the case when the section intersects
+    // page boundaries.
+    P.second = PageEntriesNum;
+    PageEntriesNum += getMipsPageCount(P.first->Size);
+  }
+  Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
+         Config->Wordsize;
+}
+
+bool MipsGotSection::empty() const {
+  // We add the .got section to the result for dynamic MIPS target because
+  // its address and properties are mentioned in the .dynamic section.
+  return Config->Relocatable;
+}
+
+uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+
+static uint64_t readUint(uint8_t *Buf) {
+  if (Config->Is64)
+    return read64(Buf, Config->Endianness);
+  return read32(Buf, Config->Endianness);
+}
+
+static void writeUint(uint8_t *Buf, uint64_t Val) {
+  if (Config->Is64)
+    write64(Buf, Val, Config->Endianness);
+  else
+    write32(Buf, Val, Config->Endianness);
+}
+
+void MipsGotSection::writeTo(uint8_t *Buf) {
+  // Set the MSB of the second GOT slot. This is not required by any
+  // MIPS ABI documentation, though.
+  //
+  // There is a comment in glibc saying that "The MSB of got[1] of a
+  // gnu object is set to identify gnu objects," and in GNU gold it
+  // says "the second entry will be used by some runtime loaders".
+  // But how this field is being used is unclear.
+  //
+  // We are not really willing to mimic other linkers behaviors
+  // without understanding why they do that, but because all files
+  // generated by GNU tools have this special GOT value, and because
+  // we've been doing this for years, it is probably a safe bet to
+  // keep doing this for now. We really need to revisit this to see
+  // if we had to do this.
+  writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
+  Buf += HeaderEntriesNum * Config->Wordsize;
+  // Write 'page address' entries to the local part of the GOT.
+  for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
+    size_t PageCount = getMipsPageCount(L.first->Size);
+    uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+    for (size_t PI = 0; PI < PageCount; ++PI) {
+      uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
+      writeUint(Entry, FirstPageAddr + PI * 0x10000);
+    }
+  }
+  Buf += PageEntriesNum * Config->Wordsize;
+  auto AddEntry = [&](const GotEntry &SA) {
+    uint8_t *Entry = Buf;
+    Buf += Config->Wordsize;
+    const SymbolBody *Body = SA.first;
+    uint64_t VA = Body->getVA(SA.second);
+    writeUint(Entry, VA);
+  };
+  std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
+  std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
+  std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry);
+  // Initialize TLS-related GOT entries. If the entry has a corresponding
+  // dynamic relocations, leave it initialized by zero. Write down adjusted
+  // TLS symbol's values otherwise. To calculate the adjustments use offsets
+  // for thread-local storage.
+  // https://www.linux-mips.org/wiki/NPTL
+  if (TlsIndexOff != -1U && !Config->Pic)
+    writeUint(Buf + TlsIndexOff, 1);
+  for (const SymbolBody *B : TlsEntries) {
+    if (!B || B->isPreemptible())
+      continue;
+    uint64_t VA = B->getVA();
+    if (B->GotIndex != -1U) {
+      uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
+      writeUint(Entry, VA - 0x7000);
+    }
+    if (B->GlobalDynIndex != -1U) {
+      uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
+      writeUint(Entry, 1);
+      Entry += Config->Wordsize;
+      writeUint(Entry, VA - 0x8000);
+    }
+  }
+}
+
+GotPltSection::GotPltSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+                       Target->GotPltEntrySize, ".got.plt") {}
+
+void GotPltSection::addEntry(SymbolBody &Sym) {
+  Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+  Entries.push_back(&Sym);
+}
+
+size_t GotPltSection::getSize() const {
+  return (Target->GotPltHeaderEntriesNum + Entries.size()) *
+         Target->GotPltEntrySize;
+}
+
+void GotPltSection::writeTo(uint8_t *Buf) {
+  Target->writeGotPltHeader(Buf);
+  Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
+  for (const SymbolBody *B : Entries) {
+    Target->writeGotPlt(Buf, *B);
+    Buf += Config->Wordsize;
+  }
+}
+
+// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
+// part of the .got.plt
+IgotPltSection::IgotPltSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+                       Target->GotPltEntrySize,
+                       Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
+
+void IgotPltSection::addEntry(SymbolBody &Sym) {
+  Sym.IsInIgot = true;
+  Sym.GotPltIndex = Entries.size();
+  Entries.push_back(&Sym);
+}
+
+size_t IgotPltSection::getSize() const {
+  return Entries.size() * Target->GotPltEntrySize;
+}
+
+void IgotPltSection::writeTo(uint8_t *Buf) {
+  for (const SymbolBody *B : Entries) {
+    Target->writeIgotPlt(Buf, *B);
+    Buf += Config->Wordsize;
+  }
+}
+
+StringTableSection::StringTableSection(StringRef Name, bool Dynamic)
+    : SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name),
+      Dynamic(Dynamic) {
+  // ELF string tables start with a NUL byte.
+  addString("");
+}
+
+// Adds a string to the string table. If HashIt is true we hash and check for
+// duplicates. It is optional because the name of global symbols are already
+// uniqued and hashing them again has a big cost for a small value: uniquing
+// them with some other string that happens to be the same.
+unsigned StringTableSection::addString(StringRef S, bool HashIt) {
+  if (HashIt) {
+    auto R = StringMap.insert(std::make_pair(S, this->Size));
+    if (!R.second)
+      return R.first->second;
+  }
+  unsigned Ret = this->Size;
+  this->Size = this->Size + S.size() + 1;
+  Strings.push_back(S);
+  return Ret;
+}
+
+void StringTableSection::writeTo(uint8_t *Buf) {
+  for (StringRef S : Strings) {
+    memcpy(Buf, S.data(), S.size());
+    Buf += S.size() + 1;
+  }
+}
+
+// Returns the number of version definition entries. Because the first entry
+// is for the version definition itself, it is the number of versioned symbols
+// plus one. Note that we don't support multiple versions yet.
+static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
+
+template <class ELFT>
+DynamicSection<ELFT>::DynamicSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize,
+                       ".dynamic") {
+  this->Entsize = ELFT::Is64Bits ? 16 : 8;
+
+  // .dynamic section is not writable on MIPS and on Fuchsia OS
+  // which passes -z rodynamic.
+  // See "Special Section" in Chapter 4 in the following document:
+  // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (Config->EMachine == EM_MIPS || Config->ZRodynamic)
+    this->Flags = SHF_ALLOC;
+
+  addEntries();
+}
+
+// There are some dynamic entries that don't depend on other sections.
+// Such entries can be set early.
+template <class ELFT> void DynamicSection<ELFT>::addEntries() {
+  // Add strings to .dynstr early so that .dynstr's size will be
+  // fixed early.
+  for (StringRef S : Config->FilterList)
+    add({DT_FILTER, InX::DynStrTab->addString(S)});
+  for (StringRef S : Config->AuxiliaryList)
+    add({DT_AUXILIARY, InX::DynStrTab->addString(S)});
+  if (!Config->Rpath.empty())
+    add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
+         InX::DynStrTab->addString(Config->Rpath)});
+  for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles())
+    if (F->isNeeded())
+      add({DT_NEEDED, InX::DynStrTab->addString(F->SoName)});
+  if (!Config->SoName.empty())
+    add({DT_SONAME, InX::DynStrTab->addString(Config->SoName)});
+
+  // Set DT_FLAGS and DT_FLAGS_1.
+  uint32_t DtFlags = 0;
+  uint32_t DtFlags1 = 0;
+  if (Config->Bsymbolic)
+    DtFlags |= DF_SYMBOLIC;
+  if (Config->ZNodelete)
+    DtFlags1 |= DF_1_NODELETE;
+  if (Config->ZNodlopen)
+    DtFlags1 |= DF_1_NOOPEN;
+  if (Config->ZNow) {
+    DtFlags |= DF_BIND_NOW;
+    DtFlags1 |= DF_1_NOW;
+  }
+  if (Config->ZOrigin) {
+    DtFlags |= DF_ORIGIN;
+    DtFlags1 |= DF_1_ORIGIN;
+  }
+
+  if (DtFlags)
+    add({DT_FLAGS, DtFlags});
+  if (DtFlags1)
+    add({DT_FLAGS_1, DtFlags1});
+
+  // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We
+  // need it for each process, so we don't write it for DSOs. The loader writes
+  // the pointer into this entry.
+  //
+  // DT_DEBUG is the only .dynamic entry that needs to be written to. Some
+  // systems (currently only Fuchsia OS) provide other means to give the
+  // debugger this information. Such systems may choose make .dynamic read-only.
+  // If the target is such a system (used -z rodynamic) don't write DT_DEBUG.
+  if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
+    add({DT_DEBUG, (uint64_t)0});
+}
+
+// Add remaining entries to complete .dynamic contents.
+template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
+  if (this->Size)
+    return; // Already finalized.
+
+  this->Link = InX::DynStrTab->getParent()->SectionIndex;
+  if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) {
+    bool IsRela = Config->IsRela;
+    add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
+    add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(),
+         Entry::SecSize});
+    add({IsRela ? DT_RELAENT : DT_RELENT,
+         uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
+
+    // MIPS dynamic loader does not support RELCOUNT tag.
+    // The problem is in the tight relation between dynamic
+    // relocations and GOT. So do not emit this tag on MIPS.
+    if (Config->EMachine != EM_MIPS) {
+      size_t NumRelativeRels = In<ELFT>::RelaDyn->getRelativeRelocCount();
+      if (Config->ZCombreloc && NumRelativeRels)
+        add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
+    }
+  }
+  if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) {
+    add({DT_JMPREL, In<ELFT>::RelaPlt});
+    add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize});
+    switch (Config->EMachine) {
+    case EM_MIPS:
+      add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt});
+      break;
+    case EM_SPARCV9:
+      add({DT_PLTGOT, In<ELFT>::Plt});
+      break;
+    default:
+      add({DT_PLTGOT, In<ELFT>::GotPlt});
+      break;
+    }
+    add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)});
+  }
+
+  add({DT_SYMTAB, InX::DynSymTab});
+  add({DT_SYMENT, sizeof(Elf_Sym)});
+  add({DT_STRTAB, InX::DynStrTab});
+  add({DT_STRSZ, InX::DynStrTab->getSize()});
+  if (!Config->ZText)
+    add({DT_TEXTREL, (uint64_t)0});
+  if (InX::GnuHashTab)
+    add({DT_GNU_HASH, InX::GnuHashTab});
+  if (In<ELFT>::HashTab)
+    add({DT_HASH, In<ELFT>::HashTab});
+
+  if (Out::PreinitArray) {
+    add({DT_PREINIT_ARRAY, Out::PreinitArray});
+    add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize});
+  }
+  if (Out::InitArray) {
+    add({DT_INIT_ARRAY, Out::InitArray});
+    add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize});
+  }
+  if (Out::FiniArray) {
+    add({DT_FINI_ARRAY, Out::FiniArray});
+    add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize});
+  }
+
+  if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Init))
+    add({DT_INIT, B});
+  if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Fini))
+    add({DT_FINI, B});
+
+  bool HasVerNeed = In<ELFT>::VerNeed->getNeedNum() != 0;
+  if (HasVerNeed || In<ELFT>::VerDef)
+    add({DT_VERSYM, In<ELFT>::VerSym});
+  if (In<ELFT>::VerDef) {
+    add({DT_VERDEF, In<ELFT>::VerDef});
+    add({DT_VERDEFNUM, getVerDefNum()});
+  }
+  if (HasVerNeed) {
+    add({DT_VERNEED, In<ELFT>::VerNeed});
+    add({DT_VERNEEDNUM, In<ELFT>::VerNeed->getNeedNum()});
+  }
+
+  if (Config->EMachine == EM_MIPS) {
+    add({DT_MIPS_RLD_VERSION, 1});
+    add({DT_MIPS_FLAGS, RHF_NOTPOT});
+    add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
+    add({DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()});
+    add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()});
+    if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry())
+      add({DT_MIPS_GOTSYM, B->DynsymIndex});
+    else
+      add({DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()});
+    add({DT_PLTGOT, InX::MipsGot});
+    if (InX::MipsRldMap)
+      add({DT_MIPS_RLD_MAP, InX::MipsRldMap});
+  }
+
+  getParent()->Link = this->Link;
+
+  // +1 for DT_NULL
+  this->Size = (Entries.size() + 1) * this->Entsize;
+}
+
+template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
+
+  for (const Entry &E : Entries) {
+    P->d_tag = E.Tag;
+    switch (E.Kind) {
+    case Entry::SecAddr:
+      P->d_un.d_ptr = E.OutSec->Addr;
+      break;
+    case Entry::InSecAddr:
+      P->d_un.d_ptr = E.InSec->getParent()->Addr + E.InSec->OutSecOff;
+      break;
+    case Entry::SecSize:
+      P->d_un.d_val = E.OutSec->Size;
+      break;
+    case Entry::SymAddr:
+      P->d_un.d_ptr = E.Sym->getVA();
+      break;
+    case Entry::PlainInt:
+      P->d_un.d_val = E.Val;
+      break;
+    }
+    ++P;
+  }
+}
+
+uint64_t DynamicReloc::getOffset() const {
+  return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec);
+}
+
+int64_t DynamicReloc::getAddend() const {
+  if (UseSymVA)
+    return Sym->getVA(Addend);
+  return Addend;
+}
+
+uint32_t DynamicReloc::getSymIndex() const {
+  if (Sym && !UseSymVA)
+    return Sym->DynsymIndex;
+  return 0;
+}
+
+template <class ELFT>
+RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
+    : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL,
+                       Config->Wordsize, Name),
+      Sort(Sort) {
+  this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+}
+
+template <class ELFT>
+void RelocationSection<ELFT>::addReloc(const DynamicReloc &Reloc) {
+  if (Reloc.Type == Target->RelativeRel)
+    ++NumRelativeRelocs;
+  Relocs.push_back(Reloc);
+}
+
+template <class ELFT, class RelTy>
+static bool compRelocations(const RelTy &A, const RelTy &B) {
+  bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel;
+  bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel;
+  if (AIsRel != BIsRel)
+    return AIsRel;
+
+  return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL);
+}
+
+template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
+  uint8_t *BufBegin = Buf;
+  for (const DynamicReloc &Rel : Relocs) {
+    auto *P = reinterpret_cast<Elf_Rela *>(Buf);
+    Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+
+    if (Config->IsRela)
+      P->r_addend = Rel.getAddend();
+    P->r_offset = Rel.getOffset();
+    if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
+      // Dynamic relocation against MIPS GOT section make deal TLS entries
+      // allocated in the end of the GOT. We need to adjust the offset to take
+      // in account 'local' and 'global' GOT entries.
+      P->r_offset += InX::MipsGot->getTlsOffset();
+    P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
+  }
+
+  if (Sort) {
+    if (Config->IsRela)
+      std::stable_sort((Elf_Rela *)BufBegin,
+                       (Elf_Rela *)BufBegin + Relocs.size(),
+                       compRelocations<ELFT, Elf_Rela>);
+    else
+      std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(),
+                       compRelocations<ELFT, Elf_Rel>);
+  }
+}
+
+template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
+  return this->Entsize * Relocs.size();
+}
+
+template <class ELFT> void RelocationSection<ELFT>::finalizeContents() {
+  this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex
+                              : InX::SymTab->getParent()->SectionIndex;
+
+  // Set required output section properties.
+  getParent()->Link = this->Link;
+}
+
+SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
+    : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
+                       StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
+                       Config->Wordsize,
+                       StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
+      StrTabSec(StrTabSec) {}
+
+// Orders symbols according to their positions in the GOT,
+// in compliance with MIPS ABI rules.
+// See "Global Offset Table" in Chapter 5 in the following document
+// for detailed description:
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+static bool sortMipsSymbols(const SymbolTableEntry &L,
+                            const SymbolTableEntry &R) {
+  // Sort entries related to non-local preemptible symbols by GOT indexes.
+  // All other entries go to the first part of GOT in arbitrary order.
+  bool LIsInLocalGot = !L.Symbol->IsInGlobalMipsGot;
+  bool RIsInLocalGot = !R.Symbol->IsInGlobalMipsGot;
+  if (LIsInLocalGot || RIsInLocalGot)
+    return !RIsInLocalGot;
+  return L.Symbol->GotIndex < R.Symbol->GotIndex;
+}
+
+// Finalize a symbol table. The ELF spec requires that all local
+// symbols precede global symbols, so we sort symbol entries in this
+// function. (For .dynsym, we don't do that because symbols for
+// dynamic linking are inherently all globals.)
+void SymbolTableBaseSection::finalizeContents() {
+  getParent()->Link = StrTabSec.getParent()->SectionIndex;
+
+  // If it is a .dynsym, there should be no local symbols, but we need
+  // to do a few things for the dynamic linker.
+  if (this->Type == SHT_DYNSYM) {
+    // Section's Info field has the index of the first non-local symbol.
+    // Because the first symbol entry is a null entry, 1 is the first.
+    getParent()->Info = 1;
+
+    if (InX::GnuHashTab) {
+      // NB: It also sorts Symbols to meet the GNU hash table requirements.
+      InX::GnuHashTab->addSymbols(Symbols);
+    } else if (Config->EMachine == EM_MIPS) {
+      std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
+    }
+
+    size_t I = 0;
+    for (const SymbolTableEntry &S : Symbols)
+      S.Symbol->DynsymIndex = ++I;
+    return;
+  }
+}
+
+void SymbolTableBaseSection::postThunkContents() {
+  if (this->Type == SHT_DYNSYM)
+    return;
+  // move all local symbols before global symbols.
+  auto It = std::stable_partition(
+      Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
+        return S.Symbol->isLocal() ||
+               S.Symbol->symbol()->computeBinding() == STB_LOCAL;
+      });
+  size_t NumLocals = It - Symbols.begin();
+  getParent()->Info = NumLocals + 1;
+}
+
+void SymbolTableBaseSection::addSymbol(SymbolBody *B) {
+  // Adding a local symbol to a .dynsym is a bug.
+  assert(this->Type != SHT_DYNSYM || !B->isLocal());
+
+  bool HashIt = B->isLocal();
+  Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)});
+}
+
+size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) {
+  auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) {
+    if (E.Symbol == Body)
+      return true;
+    // This is used for -r, so we have to handle multiple section
+    // symbols being combined.
+    if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION)
+      return Body->getOutputSection() == E.Symbol->getOutputSection();
+    return false;
+  });
+  if (I == Symbols.end())
+    return 0;
+  return I - Symbols.begin() + 1;
+}
+
+template <class ELFT>
+SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
+    : SymbolTableBaseSection(StrTabSec) {
+  this->Entsize = sizeof(Elf_Sym);
+}
+
+// Write the internal symbol table contents to the output symbol table.
+template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  // The first entry is a null entry as per the ELF spec.
+  Buf += sizeof(Elf_Sym);
+
+  auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+
+  for (SymbolTableEntry &Ent : Symbols) {
+    SymbolBody *Body = Ent.Symbol;
+
+    // Set st_info and st_other.
+    if (Body->isLocal()) {
+      ESym->setBindingAndType(STB_LOCAL, Body->Type);
+    } else {
+      ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type);
+      ESym->setVisibility(Body->symbol()->Visibility);
+    }
+
+    ESym->st_name = Ent.StrTabOffset;
+
+    // Set a section index.
+    if (const OutputSection *OutSec = Body->getOutputSection())
+      ESym->st_shndx = OutSec->SectionIndex;
+    else if (isa<DefinedRegular>(Body))
+      ESym->st_shndx = SHN_ABS;
+    else if (isa<DefinedCommon>(Body))
+      ESym->st_shndx = SHN_COMMON;
+
+    // Copy symbol size if it is a defined symbol. st_size is not significant
+    // for undefined symbols, so whether copying it or not is up to us if that's
+    // the case. We'll leave it as zero because by not setting a value, we can
+    // get the exact same outputs for two sets of input files that differ only
+    // in undefined symbol size in DSOs.
+    if (ESym->st_shndx != SHN_UNDEF)
+      ESym->st_size = Body->getSize<ELFT>();
+
+    // st_value is usually an address of a symbol, but that has a
+    // special meaining for uninstantiated common symbols (this can
+    // occur if -r is given).
+    if (!Config->DefineCommon && isa<DefinedCommon>(Body))
+      ESym->st_value = cast<DefinedCommon>(Body)->Alignment;
+    else
+      ESym->st_value = Body->getVA();
+
+    ++ESym;
+  }
+
+  // On MIPS we need to mark symbol which has a PLT entry and requires
+  // pointer equality by STO_MIPS_PLT flag. That is necessary to help
+  // dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
+  // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
+  if (Config->EMachine == EM_MIPS) {
+    auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+
+    for (SymbolTableEntry &Ent : Symbols) {
+      SymbolBody *Body = Ent.Symbol;
+      if (Body->isInPlt() && Body->NeedsPltAddr)
+        ESym->st_other |= STO_MIPS_PLT;
+
+      if (Config->Relocatable)
+        if (auto *D = dyn_cast<DefinedRegular>(Body))
+          if (D->isMipsPIC<ELFT>())
+            ESym->st_other |= STO_MIPS_PIC;
+      ++ESym;
+    }
+  }
+}
+
+// .hash and .gnu.hash sections contain on-disk hash tables that map
+// symbol names to their dynamic symbol table indices. Their purpose
+// is to help the dynamic linker resolve symbols quickly. If ELF files
+// don't have them, the dynamic linker has to do linear search on all
+// dynamic symbols, which makes programs slower. Therefore, a .hash
+// section is added to a DSO by default. A .gnu.hash is added if you
+// give the -hash-style=gnu or -hash-style=both option.
+//
+// The Unix semantics of resolving dynamic symbols is somewhat expensive.
+// Each ELF file has a list of DSOs that the ELF file depends on and a
+// list of dynamic symbols that need to be resolved from any of the
+// DSOs. That means resolving all dynamic symbols takes O(m)*O(n)
+// where m is the number of DSOs and n is the number of dynamic
+// symbols. For modern large programs, both m and n are large.  So
+// making each step faster by using hash tables substiantially
+// improves time to load programs.
+//
+// (Note that this is not the only way to design the shared library.
+// For instance, the Windows DLL takes a different approach. On
+// Windows, each dynamic symbol has a name of DLL from which the symbol
+// has to be resolved. That makes the cost of symbol resolution O(n).
+// This disables some hacky techniques you can use on Unix such as
+// LD_PRELOAD, but this is arguably better semantics than the Unix ones.)
+//
+// Due to historical reasons, we have two different hash tables, .hash
+// and .gnu.hash. They are for the same purpose, and .gnu.hash is a new
+// and better version of .hash. .hash is just an on-disk hash table, but
+// .gnu.hash has a bloom filter in addition to a hash table to skip
+// DSOs very quickly. If you are sure that your dynamic linker knows
+// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a
+// safe bet is to specify -hash-style=both for backward compatibilty.
+GnuHashTableSection::GnuHashTableSection()
+    : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") {
+}
+
+void GnuHashTableSection::finalizeContents() {
+  getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+
+  // Computes bloom filter size in word size. We want to allocate 8
+  // bits for each symbol. It must be a power of two.
+  if (Symbols.empty())
+    MaskWords = 1;
+  else
+    MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize);
+
+  Size = 16;                            // Header
+  Size += Config->Wordsize * MaskWords; // Bloom filter
+  Size += NBuckets * 4;                 // Hash buckets
+  Size += Symbols.size() * 4;           // Hash values
+}
+
+void GnuHashTableSection::writeTo(uint8_t *Buf) {
+  // Write a header.
+  write32(Buf, NBuckets, Config->Endianness);
+  write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size(),
+          Config->Endianness);
+  write32(Buf + 8, MaskWords, Config->Endianness);
+  write32(Buf + 12, getShift2(), Config->Endianness);
+  Buf += 16;
+
+  // Write a bloom filter and a hash table.
+  writeBloomFilter(Buf);
+  Buf += Config->Wordsize * MaskWords;
+  writeHashTable(Buf);
+}
+
+// This function writes a 2-bit bloom filter. This bloom filter alone
+// usually filters out 80% or more of all symbol lookups [1].
+// The dynamic linker uses the hash table only when a symbol is not
+// filtered out by a bloom filter.
+//
+// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
+//     p.9, https://www.akkadia.org/drepper/dsohowto.pdf
+void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
+  const unsigned C = Config->Wordsize * 8;
+  for (const Entry &Sym : Symbols) {
+    size_t I = (Sym.Hash / C) & (MaskWords - 1);
+    uint64_t Val = readUint(Buf + I * Config->Wordsize);
+    Val |= uint64_t(1) << (Sym.Hash % C);
+    Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C);
+    writeUint(Buf + I * Config->Wordsize, Val);
+  }
+}
+
+void GnuHashTableSection::writeHashTable(uint8_t *Buf) {
+  // Group symbols by hash value.
+  std::vector<std::vector<Entry>> Syms(NBuckets);
+  for (const Entry &Ent : Symbols)
+    Syms[Ent.Hash % NBuckets].push_back(Ent);
+
+  // Write hash buckets. Hash buckets contain indices in the following
+  // hash value table.
+  uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf);
+  for (size_t I = 0; I < NBuckets; ++I)
+    if (!Syms[I].empty())
+      write32(Buckets + I, Syms[I][0].Body->DynsymIndex, Config->Endianness);
+
+  // Write a hash value table. It represents a sequence of chains that
+  // share the same hash modulo value. The last element of each chain
+  // is terminated by LSB 1.
+  uint32_t *Values = Buckets + NBuckets;
+  size_t I = 0;
+  for (std::vector<Entry> &Vec : Syms) {
+    if (Vec.empty())
+      continue;
+    for (const Entry &Ent : makeArrayRef(Vec).drop_back())
+      write32(Values + I++, Ent.Hash & ~1, Config->Endianness);
+    write32(Values + I++, Vec.back().Hash | 1, Config->Endianness);
+  }
+}
+
+static uint32_t hashGnu(StringRef Name) {
+  uint32_t H = 5381;
+  for (uint8_t C : Name)
+    H = (H << 5) + H + C;
+  return H;
+}
+
+// Returns a number of hash buckets to accomodate given number of elements.
+// We want to choose a moderate number that is not too small (which
+// causes too many hash collisions) and not too large (which wastes
+// disk space.)
+//
+// We return a prime number because it (is believed to) achieve good
+// hash distribution.
+static size_t getBucketSize(size_t NumSymbols) {
+  // List of largest prime numbers that are not greater than 2^n + 1.
+  for (size_t N : {131071, 65521, 32749, 16381, 8191, 4093, 2039, 1021, 509,
+                   251, 127, 61, 31, 13, 7, 3, 1})
+    if (N <= NumSymbols)
+      return N;
+  return 0;
+}
+
+// Add symbols to this symbol hash table. Note that this function
+// destructively sort a given vector -- which is needed because
+// GNU-style hash table places some sorting requirements.
+void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
+  // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
+  // its type correctly.
+  std::vector<SymbolTableEntry>::iterator Mid =
+      std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
+        return S.Symbol->isUndefined();
+      });
+  if (Mid == V.end())
+    return;
+
+  for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
+    SymbolBody *B = Ent.Symbol;
+    Symbols.push_back({B, Ent.StrTabOffset, hashGnu(B->getName())});
+  }
+
+  NBuckets = getBucketSize(Symbols.size());
+  std::stable_sort(Symbols.begin(), Symbols.end(),
+                   [&](const Entry &L, const Entry &R) {
+                     return L.Hash % NBuckets < R.Hash % NBuckets;
+                   });
+
+  V.erase(Mid, V.end());
+  for (const Entry &Ent : Symbols)
+    V.push_back({Ent.Body, Ent.StrTabOffset});
+}
+
+template <class ELFT>
+HashTableSection<ELFT>::HashTableSection()
+    : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") {
+  this->Entsize = 4;
+}
+
+template <class ELFT> void HashTableSection<ELFT>::finalizeContents() {
+  getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+
+  unsigned NumEntries = 2;                       // nbucket and nchain.
+  NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries.
+
+  // Create as many buckets as there are symbols.
+  // FIXME: This is simplistic. We can try to optimize it, but implementing
+  // support for SHT_GNU_HASH is probably even more profitable.
+  NumEntries += InX::DynSymTab->getNumSymbols();
+  this->Size = NumEntries * 4;
+}
+
+template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  // A 32-bit integer type in the target endianness.
+  typedef typename ELFT::Word Elf_Word;
+
+  unsigned NumSymbols = InX::DynSymTab->getNumSymbols();
+
+  auto *P = reinterpret_cast<Elf_Word *>(Buf);
+  *P++ = NumSymbols; // nbucket
+  *P++ = NumSymbols; // nchain
+
+  Elf_Word *Buckets = P;
+  Elf_Word *Chains = P + NumSymbols;
+
+  for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
+    SymbolBody *Body = S.Symbol;
+    StringRef Name = Body->getName();
+    unsigned I = Body->DynsymIndex;
+    uint32_t Hash = hashSysV(Name) % NumSymbols;
+    Chains[I] = Buckets[Hash];
+    Buckets[Hash] = I;
+  }
+}
+
+PltSection::PltSection(size_t S)
+    : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
+      HeaderSize(S) {
+  // The PLT needs to be writable on SPARC as the dynamic linker will
+  // modify the instructions in the PLT entries.
+  if (Config->EMachine == EM_SPARCV9)
+    this->Flags |= SHF_WRITE;
+}
+
+void PltSection::writeTo(uint8_t *Buf) {
+  // At beginning of PLT but not the IPLT, we have code to call the dynamic
+  // linker to resolve dynsyms at runtime. Write such code.
+  if (HeaderSize != 0)
+    Target->writePltHeader(Buf);
+  size_t Off = HeaderSize;
+  // The IPlt is immediately after the Plt, account for this in RelOff
+  unsigned PltOff = getPltRelocOff();
+
+  for (auto &I : Entries) {
+    const SymbolBody *B = I.first;
+    unsigned RelOff = I.second + PltOff;
+    uint64_t Got = B->getGotPltVA();
+    uint64_t Plt = this->getVA() + Off;
+    Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+    Off += Target->PltEntrySize;
+  }
+}
+
+template <class ELFT> void PltSection::addEntry(SymbolBody &Sym) {
+  Sym.PltIndex = Entries.size();
+  RelocationSection<ELFT> *PltRelocSection = In<ELFT>::RelaPlt;
+  if (HeaderSize == 0) {
+    PltRelocSection = In<ELFT>::RelaIplt;
+    Sym.IsInIplt = true;
+  }
+  unsigned RelOff = PltRelocSection->getRelocOffset();
+  Entries.push_back(std::make_pair(&Sym, RelOff));
+}
+
+size_t PltSection::getSize() const {
+  return HeaderSize + Entries.size() * Target->PltEntrySize;
+}
+
+// Some architectures such as additional symbols in the PLT section. For
+// example ARM uses mapping symbols to aid disassembly
+void PltSection::addSymbols() {
+  // The PLT may have symbols defined for the Header, the IPLT has no header
+  if (HeaderSize != 0)
+    Target->addPltHeaderSymbols(this);
+  size_t Off = HeaderSize;
+  for (size_t I = 0; I < Entries.size(); ++I) {
+    Target->addPltSymbols(this, Off);
+    Off += Target->PltEntrySize;
+  }
+}
+
+unsigned PltSection::getPltRelocOff() const {
+  return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
+}
+
+GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks)
+    : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"),
+      StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {}
+
+// Iterative hash function for symbol's name is described in .gdb_index format
+// specification. Note that we use one for version 5 to 7 here, it is different
+// for version 4.
+static uint32_t hash(StringRef Str) {
+  uint32_t R = 0;
+  for (uint8_t C : Str)
+    R = R * 67 + tolower(C) - 113;
+  return R;
+}
+
+static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) {
+  std::vector<CompilationUnitEntry> Ret;
+  for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
+    Ret.push_back({CU->getOffset(), CU->getLength() + 4});
+  return Ret;
+}
+
+static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf,
+                                                 InputSection *Sec) {
+  std::vector<AddressEntry> Ret;
+
+  uint32_t CurrentCu = 0;
+  for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) {
+    DWARFAddressRangesVector Ranges;
+    CU->collectAddressRanges(Ranges);
+
+    ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
+    for (DWARFAddressRange &R : Ranges) {
+      InputSectionBase *S = Sections[R.SectionIndex];
+      if (!S || S == &InputSection::Discarded || !S->Live)
+        continue;
+      // Range list with zero size has no effect.
+      if (R.LowPC == R.HighPC)
+        continue;
+      Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCu});
+    }
+    ++CurrentCu;
+  }
+  return Ret;
+}
+
+static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf,
+                                                       bool IsLE) {
+  StringRef Data[] = {Dwarf.getGnuPubNamesSection(),
+                      Dwarf.getGnuPubTypesSection()};
+
+  std::vector<NameTypeEntry> Ret;
+  for (StringRef D : Data) {
+    DWARFDebugPubTable PubTable(D, IsLE, true);
+    for (const DWARFDebugPubTable::Set &Set : PubTable.getData())
+      for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
+        Ret.push_back({Ent.Name, Ent.Descriptor.toBits()});
+  }
+  return Ret;
+}
+
+static std::vector<InputSection *> getDebugInfoSections() {
+  std::vector<InputSection *> Ret;
+  for (InputSectionBase *S : InputSections)
+    if (InputSection *IS = dyn_cast<InputSection>(S))
+      if (IS->Name == ".debug_info")
+        Ret.push_back(IS);
+  return Ret;
+}
+
+void GdbIndexSection::buildIndex() {
+  if (Chunks.empty())
+    return;
+
+  uint32_t CuId = 0;
+  for (GdbIndexChunk &D : Chunks) {
+    for (AddressEntry &E : D.AddressArea)
+      E.CuIndex += CuId;
+
+    // Populate constant pool area.
+    for (NameTypeEntry &NameType : D.NamesAndTypes) {
+      uint32_t Hash = hash(NameType.Name);
+      size_t Offset = StringPool.add(NameType.Name);
+
+      bool IsNew;
+      GdbSymbol *Sym;
+      std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
+      if (IsNew) {
+        Sym->CuVectorIndex = CuVectors.size();
+        CuVectors.resize(CuVectors.size() + 1);
+      }
+
+      CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24));
+    }
+
+    CuId += D.CompilationUnits.size();
+  }
+}
+
+static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) {
+  GdbIndexChunk Ret;
+  Ret.DebugInfoSec = Sec;
+  Ret.CompilationUnits = readCuList(Dwarf);
+  Ret.AddressArea = readAddressArea(Dwarf, Sec);
+  Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
+  return Ret;
+}
+
+template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
+  std::vector<GdbIndexChunk> Chunks;
+  for (InputSection *Sec : getDebugInfoSections()) {
+    InputFile *F = Sec->File;
+    std::error_code EC;
+    ELFObjectFile<ELFT> Obj(F->MB, EC);
+    if (EC)
+      fatal(EC.message());
+    DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) {
+      error(toString(F) + ": error parsing DWARF data:\n>>> " +
+            toString(std::move(E)));
+      return ErrorPolicy::Continue;
+    });
+    Chunks.push_back(readDwarf(Dwarf, Sec));
+  }
+  return make<GdbIndexSection>(std::move(Chunks));
+}
+
+static size_t getCuSize(std::vector<GdbIndexChunk> &C) {
+  size_t Ret = 0;
+  for (GdbIndexChunk &D : C)
+    Ret += D.CompilationUnits.size();
+  return Ret;
+}
+
+static size_t getAddressAreaSize(std::vector<GdbIndexChunk> &C) {
+  size_t Ret = 0;
+  for (GdbIndexChunk &D : C)
+    Ret += D.AddressArea.size();
+  return Ret;
+}
+
+void GdbIndexSection::finalizeContents() {
+  if (Finalized)
+    return;
+  Finalized = true;
+
+  buildIndex();
+
+  SymbolTable.finalizeContents();
+
+  // GdbIndex header consist from version fields
+  // and 5 more fields with different kinds of offsets.
+  CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize;
+  SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize;
+
+  ConstantPoolOffset =
+      SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize;
+
+  for (std::set<uint32_t> &CuVec : CuVectors) {
+    CuVectorsOffset.push_back(CuVectorsSize);
+    CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);
+  }
+  StringPoolOffset = ConstantPoolOffset + CuVectorsSize;
+
+  StringPool.finalizeInOrder();
+}
+
+size_t GdbIndexSection::getSize() const {
+  const_cast<GdbIndexSection *>(this)->finalizeContents();
+  return StringPoolOffset + StringPool.getSize();
+}
+
+void GdbIndexSection::writeTo(uint8_t *Buf) {
+  write32le(Buf, 7);                       // Write version.
+  write32le(Buf + 4, CuListOffset);        // CU list offset.
+  write32le(Buf + 8, CuTypesOffset);       // Types CU list offset.
+  write32le(Buf + 12, CuTypesOffset);      // Address area offset.
+  write32le(Buf + 16, SymTabOffset);       // Symbol table offset.
+  write32le(Buf + 20, ConstantPoolOffset); // Constant pool offset.
+  Buf += 24;
+
+  // Write the CU list.
+  for (GdbIndexChunk &D : Chunks) {
+    for (CompilationUnitEntry &Cu : D.CompilationUnits) {
+      write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
+      write64le(Buf + 8, Cu.CuLength);
+      Buf += 16;
+    }
+  }
+
+  // Write the address area.
+  for (GdbIndexChunk &D : Chunks) {
+    for (AddressEntry &E : D.AddressArea) {
+      uint64_t BaseAddr =
+          E.Section->getParent()->Addr + E.Section->getOffset(0);
+      write64le(Buf, BaseAddr + E.LowAddress);
+      write64le(Buf + 8, BaseAddr + E.HighAddress);
+      write32le(Buf + 16, E.CuIndex);
+      Buf += 20;
+    }
+  }
+
+  // Write the symbol table.
+  for (size_t I = 0; I < SymbolTable.getCapacity(); ++I) {
+    GdbSymbol *Sym = SymbolTable.getSymbol(I);
+    if (Sym) {
+      size_t NameOffset =
+          Sym->NameOffset + StringPoolOffset - ConstantPoolOffset;
+      size_t CuVectorOffset = CuVectorsOffset[Sym->CuVectorIndex];
+      write32le(Buf, NameOffset);
+      write32le(Buf + 4, CuVectorOffset);
+    }
+    Buf += 8;
+  }
+
+  // Write the CU vectors into the constant pool.
+  for (std::set<uint32_t> &CuVec : CuVectors) {
+    write32le(Buf, CuVec.size());
+    Buf += 4;
+    for (uint32_t Val : CuVec) {
+      write32le(Buf, Val);
+      Buf += 4;
+    }
+  }
+
+  StringPool.write(Buf);
+}
+
+bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
+
+template <class ELFT>
+EhFrameHeader<ELFT>::EhFrameHeader()
+    : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
+
+// .eh_frame_hdr contains a binary search table of pointers to FDEs.
+// Each entry of the search table consists of two values,
+// the starting PC from where FDEs covers, and the FDE's address.
+// It is sorted by PC.
+template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
+  const endianness E = ELFT::TargetEndianness;
+
+  // Sort the FDE list by their PC and uniqueify. Usually there is only
+  // one FDE for a PC (i.e. function), but if ICF merges two functions
+  // into one, there can be more than one FDEs pointing to the address.
+  auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
+  std::stable_sort(Fdes.begin(), Fdes.end(), Less);
+  auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
+  Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
+
+  Buf[0] = 1;
+  Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
+  Buf[2] = DW_EH_PE_udata4;
+  Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
+  write32<E>(Buf + 4, In<ELFT>::EhFrame->getParent()->Addr - this->getVA() - 4);
+  write32<E>(Buf + 8, Fdes.size());
+  Buf += 12;
+
+  uint64_t VA = this->getVA();
+  for (FdeData &Fde : Fdes) {
+    write32<E>(Buf, Fde.Pc - VA);
+    write32<E>(Buf + 4, Fde.FdeVA - VA);
+    Buf += 8;
+  }
+}
+
+template <class ELFT> size_t EhFrameHeader<ELFT>::getSize() const {
+  // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
+  return 12 + In<ELFT>::EhFrame->NumFdes * 8;
+}
+
+template <class ELFT>
+void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
+  Fdes.push_back({Pc, FdeVA});
+}
+
+template <class ELFT> bool EhFrameHeader<ELFT>::empty() const {
+  return In<ELFT>::EhFrame->empty();
+}
+
+template <class ELFT>
+VersionDefinitionSection<ELFT>::VersionDefinitionSection()
+    : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
+                       ".gnu.version_d") {}
+
+static StringRef getFileDefName() {
+  if (!Config->SoName.empty())
+    return Config->SoName;
+  return Config->OutputFile;
+}
+
+template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
+  FileDefNameOff = InX::DynStrTab->addString(getFileDefName());
+  for (VersionDefinition &V : Config->VersionDefinitions)
+    V.NameOff = InX::DynStrTab->addString(V.Name);
+
+  getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+
+  // sh_info should be set to the number of definitions. This fact is missed in
+  // documentation, but confirmed by binutils community:
+  // https://sourceware.org/ml/binutils/2014-11/msg00355.html
+  getParent()->Info = getVerDefNum();
+}
+
+template <class ELFT>
+void VersionDefinitionSection<ELFT>::writeOne(uint8_t *Buf, uint32_t Index,
+                                              StringRef Name, size_t NameOff) {
+  auto *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
+  Verdef->vd_version = 1;
+  Verdef->vd_cnt = 1;
+  Verdef->vd_aux = sizeof(Elf_Verdef);
+  Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+  Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0);
+  Verdef->vd_ndx = Index;
+  Verdef->vd_hash = hashSysV(Name);
+
+  auto *Verdaux = reinterpret_cast<Elf_Verdaux *>(Buf + sizeof(Elf_Verdef));
+  Verdaux->vda_name = NameOff;
+  Verdaux->vda_next = 0;
+}
+
+template <class ELFT>
+void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
+  writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
+
+  for (VersionDefinition &V : Config->VersionDefinitions) {
+    Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+    writeOne(Buf, V.Id, V.Name, V.NameOff);
+  }
+
+  // Need to terminate the last version definition.
+  Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
+  Verdef->vd_next = 0;
+}
+
+template <class ELFT> size_t VersionDefinitionSection<ELFT>::getSize() const {
+  return (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
+}
+
+template <class ELFT>
+VersionTableSection<ELFT>::VersionTableSection()
+    : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
+                       ".gnu.version") {
+  this->Entsize = sizeof(Elf_Versym);
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
+  // At the moment of june 2016 GNU docs does not mention that sh_link field
+  // should be set, but Sun docs do. Also readelf relies on this field.
+  getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+}
+
+template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
+  return sizeof(Elf_Versym) * (InX::DynSymTab->getSymbols().size() + 1);
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
+  auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
+  for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
+    OutVersym->vs_index = S.Symbol->symbol()->VersionId;
+    ++OutVersym;
+  }
+}
+
+template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
+  return !In<ELFT>::VerDef && In<ELFT>::VerNeed->empty();
+}
+
+template <class ELFT>
+VersionNeedSection<ELFT>::VersionNeedSection()
+    : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
+                       ".gnu.version_r") {
+  // Identifiers in verneed section start at 2 because 0 and 1 are reserved
+  // for VER_NDX_LOCAL and VER_NDX_GLOBAL.
+  // First identifiers are reserved by verdef section if it exist.
+  NextIndex = getVerDefNum() + 1;
+}
+
+template <class ELFT>
+void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
+  auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(SS->Verdef);
+  if (!Ver) {
+    SS->symbol()->VersionId = VER_NDX_GLOBAL;
+    return;
+  }
+
+  auto *File = cast<SharedFile<ELFT>>(SS->File);
+
+  // If we don't already know that we need an Elf_Verneed for this DSO, prepare
+  // to create one by adding it to our needed list and creating a dynstr entry
+  // for the soname.
+  if (File->VerdefMap.empty())
+    Needed.push_back({File, InX::DynStrTab->addString(File->SoName)});
+  typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver];
+  // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
+  // prepare to create one by allocating a version identifier and creating a
+  // dynstr entry for the version name.
+  if (NV.Index == 0) {
+    NV.StrTab = InX::DynStrTab->addString(File->getStringTable().data() +
+                                          Ver->getAux()->vda_name);
+    NV.Index = NextIndex++;
+  }
+  SS->symbol()->VersionId = NV.Index;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
+  // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
+  auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
+  auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
+
+  for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
+    // Create an Elf_Verneed for this DSO.
+    Verneed->vn_version = 1;
+    Verneed->vn_cnt = P.first->VerdefMap.size();
+    Verneed->vn_file = P.second;
+    Verneed->vn_aux =
+        reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
+    Verneed->vn_next = sizeof(Elf_Verneed);
+    ++Verneed;
+
+    // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over
+    // VerdefMap, which will only contain references to needed version
+    // definitions. Each Elf_Vernaux is based on the information contained in
+    // the Elf_Verdef in the source DSO. This loop iterates over a std::map of
+    // pointers, but is deterministic because the pointers refer to Elf_Verdef
+    // data structures within a single input file.
+    for (auto &NV : P.first->VerdefMap) {
+      Vernaux->vna_hash = NV.first->vd_hash;
+      Vernaux->vna_flags = 0;
+      Vernaux->vna_other = NV.second.Index;
+      Vernaux->vna_name = NV.second.StrTab;
+      Vernaux->vna_next = sizeof(Elf_Vernaux);
+      ++Vernaux;
+    }
+
+    Vernaux[-1].vna_next = 0;
+  }
+  Verneed[-1].vn_next = 0;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
+  getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+  getParent()->Info = Needed.size();
+}
+
+template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
+  unsigned Size = Needed.size() * sizeof(Elf_Verneed);
+  for (const std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
+    Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
+  return Size;
+}
+
+template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
+  return getNeedNum() == 0;
+}
+
+MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type,
+                                             uint64_t Flags, uint32_t Alignment)
+    : SyntheticSection(Flags, Type, Alignment, Name),
+      Builder(StringTableBuilder::RAW, Alignment) {}
+
+void MergeSyntheticSection::addSection(MergeInputSection *MS) {
+  MS->Parent = this;
+  Sections.push_back(MS);
+}
+
+void MergeSyntheticSection::writeTo(uint8_t *Buf) { Builder.write(Buf); }
+
+bool MergeSyntheticSection::shouldTailMerge() const {
+  return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
+}
+
+void MergeSyntheticSection::finalizeTailMerge() {
+  // Add all string pieces to the string table builder to create section
+  // contents.
+  for (MergeInputSection *Sec : Sections)
+    for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+      if (Sec->Pieces[I].Live)
+        Builder.add(Sec->getData(I));
+
+  // Fix the string table content. After this, the contents will never change.
+  Builder.finalize();
+
+  // finalize() fixed tail-optimized strings, so we can now get
+  // offsets of strings. Get an offset for each string and save it
+  // to a corresponding StringPiece for easy access.
+  for (MergeInputSection *Sec : Sections)
+    for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+      if (Sec->Pieces[I].Live)
+        Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
+}
+
+void MergeSyntheticSection::finalizeNoTailMerge() {
+  // Add all string pieces to the string table builder to create section
+  // contents. Because we are not tail-optimizing, offsets of strings are
+  // fixed when they are added to the builder (string table builder contains
+  // a hash table from strings to offsets).
+  for (MergeInputSection *Sec : Sections)
+    for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+      if (Sec->Pieces[I].Live)
+        Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
+
+  Builder.finalizeInOrder();
+}
+
+void MergeSyntheticSection::finalizeContents() {
+  if (shouldTailMerge())
+    finalizeTailMerge();
+  else
+    finalizeNoTailMerge();
+}
+
+size_t MergeSyntheticSection::getSize() const { return Builder.getSize(); }
+
+// This function decompresses compressed sections and scans over the input
+// sections to create mergeable synthetic sections. It removes
+// MergeInputSections from the input section array and adds new synthetic
+// sections at the location of the first input section that it replaces. It then
+// finalizes each synthetic section in order to compute an output offset for
+// each piece of each input section.
+void elf::decompressAndMergeSections() {
+  // splitIntoPieces needs to be called on each MergeInputSection before calling
+  // finalizeContents(). Do that first.
+  parallelForEach(InputSections.begin(), InputSections.end(),
+                  [](InputSectionBase *S) {
+                    if (!S->Live)
+                      return;
+                    if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
+                      S->uncompress();
+                    if (auto *MS = dyn_cast<MergeInputSection>(S))
+                      MS->splitIntoPieces();
+                  });
+
+  std::vector<MergeSyntheticSection *> MergeSections;
+  for (InputSectionBase *&S : InputSections) {
+    MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
+    if (!MS)
+      continue;
+
+    // We do not want to handle sections that are not alive, so just remove
+    // them instead of trying to merge.
+    if (!MS->Live)
+      continue;
+
+    StringRef OutsecName = getOutputSectionName(MS->Name);
+    uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP;
+    uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
+
+    auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
+      return Sec->Name == OutsecName && Sec->Flags == Flags &&
+             Sec->Alignment == Alignment;
+    });
+    if (I == MergeSections.end()) {
+      MergeSyntheticSection *Syn =
+          make<MergeSyntheticSection>(OutsecName, MS->Type, Flags, Alignment);
+      MergeSections.push_back(Syn);
+      I = std::prev(MergeSections.end());
+      S = Syn;
+    } else {
+      S = nullptr;
+    }
+    (*I)->addSection(MS);
+  }
+  for (auto *MS : MergeSections)
+    MS->finalizeContents();
+
+  std::vector<InputSectionBase *> &V = InputSections;
+  V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
+}
+
+MipsRldMapSection::MipsRldMapSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
+                       ".rld_map") {}
+
+ARMExidxSentinelSection::ARMExidxSentinelSection()
+    : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
+                       Config->Wordsize, ".ARM.exidx") {}
+
+// Write a terminating sentinel entry to the end of the .ARM.exidx table.
+// This section will have been sorted last in the .ARM.exidx table.
+// This table entry will have the form:
+// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
+// The sentinel must have the PREL31 value of an address higher than any
+// address described by any other table entry.
+void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
+  // The Sections are sorted in order of ascending PREL31 address with the
+  // sentinel last. We need to find the InputSection that precedes the
+  // sentinel. By construction the Sentinel is in the last
+  // InputSectionDescription as the InputSection that precedes it.
+  OutputSectionCommand *C = Script->getCmd(getParent());
+  auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(),
+                          [](const BaseCommand *Base) {
+                            return isa<InputSectionDescription>(Base);
+                          });
+  auto L = cast<InputSectionDescription>(*ISD);
+  InputSection *Highest = L->Sections[L->Sections.size() - 2];
+  InputSection *LS = Highest->getLinkOrderDep();
+  uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize());
+  uint64_t P = getVA();
+  Target->relocateOne(Buf, R_ARM_PREL31, S - P);
+  write32le(Buf + 4, 0x1);
+}
+
+ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
+    : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
+                       Config->Wordsize, ".text.thunk") {
+  this->Parent = OS;
+  this->OutSecOff = Off;
+}
+
+void ThunkSection::addThunk(Thunk *T) {
+  uint64_t Off = alignTo(Size, T->Alignment);
+  T->Offset = Off;
+  Thunks.push_back(T);
+  T->addSymbols(*this);
+  Size = Off + T->size();
+}
+
+void ThunkSection::writeTo(uint8_t *Buf) {
+  for (const Thunk *T : Thunks)
+    T->writeTo(Buf + T->Offset, *this);
+}
+
+InputSection *ThunkSection::getTargetInputSection() const {
+  const Thunk *T = Thunks.front();
+  return T->getTargetInputSection();
+}
+
+InputSection *InX::ARMAttributes;
+BssSection *InX::Bss;
+BssSection *InX::BssRelRo;
+BuildIdSection *InX::BuildId;
+InputSection *InX::Common;
+SyntheticSection *InX::Dynamic;
+StringTableSection *InX::DynStrTab;
+SymbolTableBaseSection *InX::DynSymTab;
+InputSection *InX::Interp;
+GdbIndexSection *InX::GdbIndex;
+GotSection *InX::Got;
+GotPltSection *InX::GotPlt;
+GnuHashTableSection *InX::GnuHashTab;
+IgotPltSection *InX::IgotPlt;
+MipsGotSection *InX::MipsGot;
+MipsRldMapSection *InX::MipsRldMap;
+PltSection *InX::Plt;
+PltSection *InX::Iplt;
+StringTableSection *InX::ShStrTab;
+StringTableSection *InX::StrTab;
+SymbolTableBaseSection *InX::SymTab;
+
+template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+
+template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF64BE>(SymbolBody &Sym);
+
+template InputSection *elf::createCommonSection<ELF32LE>();
+template InputSection *elf::createCommonSection<ELF32BE>();
+template InputSection *elf::createCommonSection<ELF64LE>();
+template InputSection *elf::createCommonSection<ELF64BE>();
+
+template MergeInputSection *elf::createCommentSection<ELF32LE>();
+template MergeInputSection *elf::createCommentSection<ELF32BE>();
+template MergeInputSection *elf::createCommentSection<ELF64LE>();
+template MergeInputSection *elf::createCommentSection<ELF64BE>();
+
+template class elf::MipsAbiFlagsSection<ELF32LE>;
+template class elf::MipsAbiFlagsSection<ELF32BE>;
+template class elf::MipsAbiFlagsSection<ELF64LE>;
+template class elf::MipsAbiFlagsSection<ELF64BE>;
+
+template class elf::MipsOptionsSection<ELF32LE>;
+template class elf::MipsOptionsSection<ELF32BE>;
+template class elf::MipsOptionsSection<ELF64LE>;
+template class elf::MipsOptionsSection<ELF64BE>;
+
+template class elf::MipsReginfoSection<ELF32LE>;
+template class elf::MipsReginfoSection<ELF32BE>;
+template class elf::MipsReginfoSection<ELF64LE>;
+template class elf::MipsReginfoSection<ELF64BE>;
+
+template class elf::DynamicSection<ELF32LE>;
+template class elf::DynamicSection<ELF32BE>;
+template class elf::DynamicSection<ELF64LE>;
+template class elf::DynamicSection<ELF64BE>;
+
+template class elf::RelocationSection<ELF32LE>;
+template class elf::RelocationSection<ELF32BE>;
+template class elf::RelocationSection<ELF64LE>;
+template class elf::RelocationSection<ELF64BE>;
+
+template class elf::SymbolTableSection<ELF32LE>;
+template class elf::SymbolTableSection<ELF32BE>;
+template class elf::SymbolTableSection<ELF64LE>;
+template class elf::SymbolTableSection<ELF64BE>;
+
+template class elf::HashTableSection<ELF32LE>;
+template class elf::HashTableSection<ELF32BE>;
+template class elf::HashTableSection<ELF64LE>;
+template class elf::HashTableSection<ELF64BE>;
+
+template class elf::EhFrameHeader<ELF32LE>;
+template class elf::EhFrameHeader<ELF32BE>;
+template class elf::EhFrameHeader<ELF64LE>;
+template class elf::EhFrameHeader<ELF64BE>;
+
+template class elf::VersionTableSection<ELF32LE>;
+template class elf::VersionTableSection<ELF32BE>;
+template class elf::VersionTableSection<ELF64LE>;
+template class elf::VersionTableSection<ELF64BE>;
+
+template class elf::VersionNeedSection<ELF32LE>;
+template class elf::VersionNeedSection<ELF32BE>;
+template class elf::VersionNeedSection<ELF64LE>;
+template class elf::VersionNeedSection<ELF64BE>;
+
+template class elf::VersionDefinitionSection<ELF32LE>;
+template class elf::VersionDefinitionSection<ELF32BE>;
+template class elf::VersionDefinitionSection<ELF64LE>;
+template class elf::VersionDefinitionSection<ELF64BE>;
+
+template class elf::EhFrameSection<ELF32LE>;
+template class elf::EhFrameSection<ELF32BE>;
+template class elf::EhFrameSection<ELF64LE>;
+template class elf::EhFrameSection<ELF64BE>;
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
new file mode 100644 (file)
index 0000000..ddd8ca9
--- /dev/null
@@ -0,0 +1,805 @@
+//===- SyntheticSection.h ---------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Synthetic sections represent chunks of linker-created data. If you
+// need to create a chunk of data that to be included in some section
+// in the result, you probably want to create that as a synthetic section.
+//
+// Synthetic sections are designed as input sections as opposed to
+// output sections because we want to allow them to be manipulated
+// using linker scripts just like other input sections from regular
+// files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYNTHETIC_SECTION_H
+#define LLD_ELF_SYNTHETIC_SECTION_H
+
+#include "EhFrame.h"
+#include "GdbIndex.h"
+#include "InputSection.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/MC/StringTableBuilder.h"
+
+#include <set>
+
+namespace lld {
+namespace elf {
+
+class SyntheticSection : public InputSection {
+public:
+  SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+                   StringRef Name)
+      : InputSection(Flags, Type, Alignment, {}, Name,
+                     InputSectionBase::Synthetic) {
+    this->Live = true;
+  }
+
+  virtual ~SyntheticSection() = default;
+  virtual void writeTo(uint8_t *Buf) = 0;
+  virtual size_t getSize() const = 0;
+  virtual void finalizeContents() {}
+  // If the section has the SHF_ALLOC flag and the size may be changed if
+  // thunks are added, update the section size.
+  virtual void updateAllocSize() {}
+  // If any additional finalization of contents are needed post thunk creation.
+  virtual void postThunkContents() {}
+  virtual bool empty() const { return false; }
+  uint64_t getVA() const;
+
+  static bool classof(const SectionBase *D) {
+    return D->kind() == InputSectionBase::Synthetic;
+  }
+};
+
+struct CieRecord {
+  EhSectionPiece *Piece = nullptr;
+  std::vector<EhSectionPiece *> FdePieces;
+};
+
+// Section for .eh_frame.
+template <class ELFT> class EhFrameSection final : public SyntheticSection {
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+
+  void updateAlignment(uint64_t Val) {
+    if (Val > this->Alignment)
+      this->Alignment = Val;
+  }
+
+public:
+  EhFrameSection();
+  void writeTo(uint8_t *Buf) override;
+  void finalizeContents() override;
+  bool empty() const override { return Sections.empty(); }
+  size_t getSize() const override { return Size; }
+
+  void addSection(InputSectionBase *S);
+
+  size_t NumFdes = 0;
+
+  std::vector<EhInputSection *> Sections;
+
+private:
+  uint64_t Size = 0;
+  template <class RelTy>
+  void addSectionAux(EhInputSection *S, llvm::ArrayRef<RelTy> Rels);
+
+  template <class RelTy>
+  CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
+
+  template <class RelTy>
+  bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
+
+  uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
+
+  std::vector<CieRecord *> Cies;
+
+  // CIE records are uniquified by their contents and personality functions.
+  llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
+};
+
+class GotSection : public SyntheticSection {
+public:
+  GotSection();
+  size_t getSize() const override { return Size; }
+  void finalizeContents() override;
+  bool empty() const override;
+  void writeTo(uint8_t *Buf) override;
+
+  void addEntry(SymbolBody &Sym);
+  bool addDynTlsEntry(SymbolBody &Sym);
+  bool addTlsIndex();
+  uint64_t getGlobalDynAddr(const SymbolBody &B) const;
+  uint64_t getGlobalDynOffset(const SymbolBody &B) const;
+
+  uint64_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
+  uint32_t getTlsIndexOff() const { return TlsIndexOff; }
+
+  // Flag to force GOT to be in output if we have relocations
+  // that relies on its address.
+  bool HasGotOffRel = false;
+
+protected:
+  size_t NumEntries = 0;
+  uint32_t TlsIndexOff = -1;
+  uint64_t Size = 0;
+};
+
+// .note.gnu.build-id section.
+class BuildIdSection : public SyntheticSection {
+  // First 16 bytes are a header.
+  static const unsigned HeaderSize = 16;
+
+public:
+  BuildIdSection();
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return HeaderSize + HashSize; }
+  void writeBuildId(llvm::ArrayRef<uint8_t> Buf);
+
+private:
+  void computeHash(llvm::ArrayRef<uint8_t> Buf,
+                   std::function<void(uint8_t *, ArrayRef<uint8_t>)> Hash);
+
+  size_t HashSize;
+  uint8_t *HashBuf;
+};
+
+// BssSection is used to reserve space for copy relocations and common symbols.
+// We create three instances of this class for .bss, .bss.rel.ro and "COMMON",
+// that are used for writable symbols, read-only symbols and common symbols,
+// respectively.
+class BssSection final : public SyntheticSection {
+public:
+  BssSection(StringRef Name);
+  void writeTo(uint8_t *) override {}
+  bool empty() const override { return getSize() == 0; }
+  size_t reserveSpace(uint64_t Size, uint32_t Alignment);
+  size_t getSize() const override { return Size; }
+
+private:
+  uint64_t Size = 0;
+};
+
+class MipsGotSection final : public SyntheticSection {
+public:
+  MipsGotSection();
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return Size; }
+  void updateAllocSize() override;
+  void finalizeContents() override;
+  bool empty() const override;
+  void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr);
+  bool addDynTlsEntry(SymbolBody &Sym);
+  bool addTlsIndex();
+  uint64_t getPageEntryOffset(const SymbolBody &B, int64_t Addend) const;
+  uint64_t getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const;
+  uint64_t getGlobalDynOffset(const SymbolBody &B) const;
+
+  // Returns the symbol which corresponds to the first entry of the global part
+  // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
+  // table properties.
+  // Returns nullptr if the global part is empty.
+  const SymbolBody *getFirstGlobalEntry() const;
+
+  // Returns the number of entries in the local part of GOT including
+  // the number of reserved entries.
+  unsigned getLocalEntriesNum() const;
+
+  // Returns offset of TLS part of the MIPS GOT table. This part goes
+  // after 'local' and 'global' entries.
+  uint64_t getTlsOffset() const;
+
+  uint32_t getTlsIndexOff() const { return TlsIndexOff; }
+
+  uint64_t getGp() const;
+
+private:
+  // MIPS GOT consists of three parts: local, global and tls. Each part
+  // contains different types of entries. Here is a layout of GOT:
+  // - Header entries                |
+  // - Page entries                  |   Local part
+  // - Local entries (16-bit access) |
+  // - Local entries (32-bit access) |
+  // - Normal global entries         ||  Global part
+  // - Reloc-only global entries     ||
+  // - TLS entries                   ||| TLS part
+  //
+  // Header:
+  //   Two entries hold predefined value 0x0 and 0x80000000.
+  // Page entries:
+  //   These entries created by R_MIPS_GOT_PAGE relocation and R_MIPS_GOT16
+  //   relocation against local symbols. They are initialized by higher 16-bit
+  //   of the corresponding symbol's value. So each 64kb of address space
+  //   requires a single GOT entry.
+  // Local entries (16-bit access):
+  //   These entries created by GOT relocations against global non-preemptible
+  //   symbols so dynamic linker is not necessary to resolve the symbol's
+  //   values. "16-bit access" means that corresponding relocations address
+  //   GOT using 16-bit index. Each unique Symbol-Addend pair has its own
+  //   GOT entry.
+  // Local entries (32-bit access):
+  //   These entries are the same as above but created by relocations which
+  //   address GOT using 32-bit index (R_MIPS_GOT_HI16/LO16 etc).
+  // Normal global entries:
+  //   These entries created by GOT relocations against preemptible global
+  //   symbols. They need to be initialized by dynamic linker and they ordered
+  //   exactly as the corresponding entries in the dynamic symbols table.
+  // Reloc-only global entries:
+  //   These entries created for symbols that are referenced by dynamic
+  //   relocations R_MIPS_REL32. These entries are not accessed with gp-relative
+  //   addressing, but MIPS ABI requires that these entries be present in GOT.
+  // TLS entries:
+  //   Entries created by TLS relocations.
+
+  // Number of "Header" entries.
+  static const unsigned HeaderEntriesNum = 2;
+  // Number of allocated "Page" entries.
+  uint32_t PageEntriesNum = 0;
+  // Map output sections referenced by MIPS GOT relocations
+  // to the first index of "Page" entries allocated for this section.
+  llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap;
+
+  typedef std::pair<const SymbolBody *, uint64_t> GotEntry;
+  typedef std::vector<GotEntry> GotEntries;
+  // Map from Symbol-Addend pair to the GOT index.
+  llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
+  // Local entries (16-bit access).
+  GotEntries LocalEntries;
+  // Local entries (32-bit access).
+  GotEntries LocalEntries32;
+
+  // Normal and reloc-only global entries.
+  GotEntries GlobalEntries;
+
+  // TLS entries.
+  std::vector<const SymbolBody *> TlsEntries;
+
+  uint32_t TlsIndexOff = -1;
+  uint64_t Size = 0;
+};
+
+class GotPltSection final : public SyntheticSection {
+public:
+  GotPltSection();
+  void addEntry(SymbolBody &Sym);
+  size_t getSize() const override;
+  void writeTo(uint8_t *Buf) override;
+  bool empty() const override { return Entries.empty(); }
+
+private:
+  std::vector<const SymbolBody *> Entries;
+};
+
+// The IgotPltSection is a Got associated with the PltSection for GNU Ifunc
+// Symbols that will be relocated by Target->IRelativeRel.
+// On most Targets the IgotPltSection will immediately follow the GotPltSection
+// on ARM the IgotPltSection will immediately follow the GotSection.
+class IgotPltSection final : public SyntheticSection {
+public:
+  IgotPltSection();
+  void addEntry(SymbolBody &Sym);
+  size_t getSize() const override;
+  void writeTo(uint8_t *Buf) override;
+  bool empty() const override { return Entries.empty(); }
+
+private:
+  std::vector<const SymbolBody *> Entries;
+};
+
+class StringTableSection final : public SyntheticSection {
+public:
+  StringTableSection(StringRef Name, bool Dynamic);
+  unsigned addString(StringRef S, bool HashIt = true);
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return Size; }
+  bool isDynamic() const { return Dynamic; }
+
+private:
+  const bool Dynamic;
+
+  uint64_t Size = 0;
+
+  llvm::DenseMap<StringRef, unsigned> StringMap;
+  std::vector<StringRef> Strings;
+};
+
+class DynamicReloc {
+public:
+  DynamicReloc(uint32_t Type, const InputSectionBase *InputSec,
+               uint64_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+               int64_t Addend)
+      : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
+        UseSymVA(UseSymVA), Addend(Addend) {}
+
+  uint64_t getOffset() const;
+  int64_t getAddend() const;
+  uint32_t getSymIndex() const;
+  const InputSectionBase *getInputSec() const { return InputSec; }
+
+  uint32_t Type;
+
+private:
+  SymbolBody *Sym;
+  const InputSectionBase *InputSec = nullptr;
+  uint64_t OffsetInSec;
+  bool UseSymVA;
+  int64_t Addend;
+};
+
+template <class ELFT> class DynamicSection final : public SyntheticSection {
+  typedef typename ELFT::Dyn Elf_Dyn;
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+
+  // The .dynamic section contains information for the dynamic linker.
+  // The section consists of fixed size entries, which consist of
+  // type and value fields. Value are one of plain integers, symbol
+  // addresses, or section addresses. This struct represents the entry.
+  struct Entry {
+    int32_t Tag;
+    union {
+      OutputSection *OutSec;
+      InputSection *InSec;
+      uint64_t Val;
+      const SymbolBody *Sym;
+    };
+    enum KindT { SecAddr, SecSize, SymAddr, PlainInt, InSecAddr } Kind;
+    Entry(int32_t Tag, OutputSection *OutSec, KindT Kind = SecAddr)
+        : Tag(Tag), OutSec(OutSec), Kind(Kind) {}
+    Entry(int32_t Tag, InputSection *Sec)
+        : Tag(Tag), InSec(Sec), Kind(InSecAddr) {}
+    Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {}
+    Entry(int32_t Tag, const SymbolBody *Sym)
+        : Tag(Tag), Sym(Sym), Kind(SymAddr) {}
+  };
+
+  // finalizeContents() fills this vector with the section contents.
+  std::vector<Entry> Entries;
+
+public:
+  DynamicSection();
+  void finalizeContents() override;
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return Size; }
+
+private:
+  void addEntries();
+  void add(Entry E) { Entries.push_back(E); }
+  uint64_t Size = 0;
+};
+
+template <class ELFT> class RelocationSection final : public SyntheticSection {
+  typedef typename ELFT::Rel Elf_Rel;
+  typedef typename ELFT::Rela Elf_Rela;
+
+public:
+  RelocationSection(StringRef Name, bool Sort);
+  void addReloc(const DynamicReloc &Reloc);
+  unsigned getRelocOffset();
+  void finalizeContents() override;
+  void writeTo(uint8_t *Buf) override;
+  bool empty() const override { return Relocs.empty(); }
+  size_t getSize() const override { return Relocs.size() * this->Entsize; }
+  size_t getRelativeRelocCount() const { return NumRelativeRelocs; }
+
+private:
+  bool Sort;
+  size_t NumRelativeRelocs = 0;
+  std::vector<DynamicReloc> Relocs;
+};
+
+struct SymbolTableEntry {
+  SymbolBody *Symbol;
+  size_t StrTabOffset;
+};
+
+class SymbolTableBaseSection : public SyntheticSection {
+public:
+  SymbolTableBaseSection(StringTableSection &StrTabSec);
+  void finalizeContents() override;
+  void postThunkContents() override;
+  size_t getSize() const override { return getNumSymbols() * Entsize; }
+  void addSymbol(SymbolBody *Body);
+  unsigned getNumSymbols() const { return Symbols.size() + 1; }
+  size_t getSymbolIndex(SymbolBody *Body);
+  ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
+
+protected:
+  // A vector of symbols and their string table offsets.
+  std::vector<SymbolTableEntry> Symbols;
+
+  StringTableSection &StrTabSec;
+};
+
+template <class ELFT>
+class SymbolTableSection final : public SymbolTableBaseSection {
+  typedef typename ELFT::Sym Elf_Sym;
+
+public:
+  SymbolTableSection(StringTableSection &StrTabSec);
+  void writeTo(uint8_t *Buf) override;
+};
+
+// Outputs GNU Hash section. For detailed explanation see:
+// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
+class GnuHashTableSection final : public SyntheticSection {
+public:
+  GnuHashTableSection();
+  void finalizeContents() override;
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return Size; }
+
+  // Adds symbols to the hash table.
+  // Sorts the input to satisfy GNU hash section requirements.
+  void addSymbols(std::vector<SymbolTableEntry> &Symbols);
+
+private:
+  size_t getShift2() const { return Config->Is64 ? 6 : 5; }
+
+  void writeBloomFilter(uint8_t *Buf);
+  void writeHashTable(uint8_t *Buf);
+
+  struct Entry {
+    SymbolBody *Body;
+    size_t StrTabOffset;
+    uint32_t Hash;
+  };
+
+  std::vector<Entry> Symbols;
+  size_t MaskWords;
+  size_t NBuckets = 0;
+  size_t Size = 0;
+};
+
+template <class ELFT> class HashTableSection final : public SyntheticSection {
+public:
+  HashTableSection();
+  void finalizeContents() override;
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override { return Size; }
+
+private:
+  size_t Size = 0;
+};
+
+// The PltSection is used for both the Plt and Iplt. The former always has a
+// header as its first entry that is used at run-time to resolve lazy binding.
+// The latter is used for GNU Ifunc symbols, that will be subject to a
+// Target->IRelativeRel.
+class PltSection : public SyntheticSection {
+public:
+  PltSection(size_t HeaderSize);
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override;
+  bool empty() const override { return Entries.empty(); }
+  void addSymbols();
+
+  template <class ELFT> void addEntry(SymbolBody &Sym);
+
+private:
+  void writeHeader(uint8_t *Buf){};
+  void addHeaderSymbols(){};
+  unsigned getPltRelocOff() const;
+  std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
+  // Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero
+  size_t HeaderSize;
+};
+
+class GdbIndexSection final : public SyntheticSection {
+  const unsigned OffsetTypeSize = 4;
+  const unsigned CuListOffset = 6 * OffsetTypeSize;
+  const unsigned CompilationUnitSize = 16;
+  const unsigned AddressEntrySize = 16 + OffsetTypeSize;
+  const unsigned SymTabEntrySize = 2 * OffsetTypeSize;
+
+public:
+  GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks);
+  void finalizeContents() override;
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override;
+  bool empty() const override;
+
+  // Symbol table is a hash table for types and names.
+  // It is the area of gdb index.
+  GdbHashTab SymbolTable;
+
+  // CU vector is a part of constant pool area of section.
+  std::vector<std::set<uint32_t>> CuVectors;
+
+  // String pool is also a part of constant pool, it follows CU vectors.
+  llvm::StringTableBuilder StringPool;
+
+  // Each chunk contains information gathered from a debug sections of single
+  // object and used to build different areas of gdb index.
+  std::vector<GdbIndexChunk> Chunks;
+
+private:
+  void buildIndex();
+
+  uint32_t CuTypesOffset;
+  uint32_t SymTabOffset;
+  uint32_t ConstantPoolOffset;
+  uint32_t StringPoolOffset;
+
+  size_t CuVectorsSize = 0;
+  std::vector<size_t> CuVectorsOffset;
+
+  bool Finalized = false;
+};
+
+template <class ELFT> GdbIndexSection *createGdbIndex();
+
+// --eh-frame-hdr option tells linker to construct a header for all the
+// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
+// and also to a PT_GNU_EH_FRAME segment.
+// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
+// calling dl_iterate_phdr.
+// This section contains a lookup table for quick binary search of FDEs.
+// Detailed info about internals can be found in Ian Lance Taylor's blog:
+// http://www.airs.com/blog/archives/460 (".eh_frame")
+// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
+template <class ELFT> class EhFrameHeader final : public SyntheticSection {
+public:
+  EhFrameHeader();
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override;
+  void addFde(uint32_t Pc, uint32_t FdeVA);
+  bool empty() const override;
+
+private:
+  struct FdeData {
+    uint32_t Pc;
+    uint32_t FdeVA;
+  };
+
+  std::vector<FdeData> Fdes;
+};
+
+// For more information about .gnu.version and .gnu.version_r see:
+// https://www.akkadia.org/drepper/symbol-versioning
+
+// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall
+// contain symbol version definitions. The number of entries in this section
+// shall be contained in the DT_VERDEFNUM entry of the .dynamic section.
+// The section shall contain an array of Elf_Verdef structures, optionally
+// followed by an array of Elf_Verdaux structures.
+template <class ELFT>
+class VersionDefinitionSection final : public SyntheticSection {
+  typedef typename ELFT::Verdef Elf_Verdef;
+  typedef typename ELFT::Verdaux Elf_Verdaux;
+
+public:
+  VersionDefinitionSection();
+  void finalizeContents() override;
+  size_t getSize() const override;
+  void writeTo(uint8_t *Buf) override;
+
+private:
+  void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff);
+
+  unsigned FileDefNameOff;
+};
+
+// The .gnu.version section specifies the required version of each symbol in the
+// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol
+// table entry. An Elf_Versym is just a 16-bit integer that refers to a version
+// identifier defined in the either .gnu.version_r or .gnu.version_d section.
+// The values 0 and 1 are reserved. All other values are used for versions in
+// the own object or in any of the dependencies.
+template <class ELFT>
+class VersionTableSection final : public SyntheticSection {
+  typedef typename ELFT::Versym Elf_Versym;
+
+public:
+  VersionTableSection();
+  void finalizeContents() override;
+  size_t getSize() const override;
+  void writeTo(uint8_t *Buf) override;
+  bool empty() const override;
+};
+
+// The .gnu.version_r section defines the version identifiers used by
+// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each
+// Elf_Verneed specifies the version requirements for a single DSO, and contains
+// a reference to a linked list of Elf_Vernaux data structures which define the
+// mapping from version identifiers to version names.
+template <class ELFT> class VersionNeedSection final : public SyntheticSection {
+  typedef typename ELFT::Verneed Elf_Verneed;
+  typedef typename ELFT::Vernaux Elf_Vernaux;
+
+  // A vector of shared files that need Elf_Verneed data structures and the
+  // string table offsets of their sonames.
+  std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed;
+
+  // The next available version identifier.
+  unsigned NextIndex;
+
+public:
+  VersionNeedSection();
+  void addSymbol(SharedSymbol *SS);
+  void finalizeContents() override;
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override;
+  size_t getNeedNum() const { return Needed.size(); }
+  bool empty() const override;
+};
+
+// MergeSyntheticSection is a class that allows us to put mergeable sections
+// with different attributes in a single output sections. To do that
+// we put them into MergeSyntheticSection synthetic input sections which are
+// attached to regular output sections.
+class MergeSyntheticSection final : public SyntheticSection {
+public:
+  MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags,
+                        uint32_t Alignment);
+  void addSection(MergeInputSection *MS);
+  void writeTo(uint8_t *Buf) override;
+  void finalizeContents() override;
+  bool shouldTailMerge() const;
+  size_t getSize() const override;
+
+private:
+  void finalizeTailMerge();
+  void finalizeNoTailMerge();
+
+  llvm::StringTableBuilder Builder;
+  std::vector<MergeInputSection *> Sections;
+};
+
+// .MIPS.abiflags section.
+template <class ELFT>
+class MipsAbiFlagsSection final : public SyntheticSection {
+  typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
+
+public:
+  static MipsAbiFlagsSection *create();
+
+  MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags);
+  size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); }
+  void writeTo(uint8_t *Buf) override;
+
+private:
+  Elf_Mips_ABIFlags Flags;
+};
+
+// .MIPS.options section.
+template <class ELFT> class MipsOptionsSection final : public SyntheticSection {
+  typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+  typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+  static MipsOptionsSection *create();
+
+  MipsOptionsSection(Elf_Mips_RegInfo Reginfo);
+  void writeTo(uint8_t *Buf) override;
+
+  size_t getSize() const override {
+    return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+  }
+
+private:
+  Elf_Mips_RegInfo Reginfo;
+};
+
+// MIPS .reginfo section.
+template <class ELFT> class MipsReginfoSection final : public SyntheticSection {
+  typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+  static MipsReginfoSection *create();
+
+  MipsReginfoSection(Elf_Mips_RegInfo Reginfo);
+  size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); }
+  void writeTo(uint8_t *Buf) override;
+
+private:
+  Elf_Mips_RegInfo Reginfo;
+};
+
+// This is a MIPS specific section to hold a space within the data segment
+// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
+// See "Dynamic section" in Chapter 5 in the following document:
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+class MipsRldMapSection : public SyntheticSection {
+public:
+  MipsRldMapSection();
+  size_t getSize() const override { return Config->Wordsize; }
+  void writeTo(uint8_t *Buf) override {}
+};
+
+class ARMExidxSentinelSection : public SyntheticSection {
+public:
+  ARMExidxSentinelSection();
+  size_t getSize() const override { return 8; }
+  void writeTo(uint8_t *Buf) override;
+};
+
+// A container for one or more linker generated thunks. Instances of these
+// thunks including ARM interworking and Mips LA25 PI to non-PI thunks.
+class ThunkSection : public SyntheticSection {
+public:
+  // ThunkSection in OS, with desired OutSecOff of Off
+  ThunkSection(OutputSection *OS, uint64_t Off);
+
+  // Add a newly created Thunk to this container:
+  // Thunk is given offset from start of this InputSection
+  // Thunk defines a symbol in this InputSection that can be used as target
+  // of a relocation
+  void addThunk(Thunk *T);
+  size_t getSize() const override { return Size; }
+  void writeTo(uint8_t *Buf) override;
+  InputSection *getTargetInputSection() const;
+
+private:
+  std::vector<const Thunk *> Thunks;
+  size_t Size = 0;
+};
+
+template <class ELFT> InputSection *createCommonSection();
+InputSection *createInterpSection();
+template <class ELFT> MergeInputSection *createCommentSection();
+void decompressAndMergeSections();
+
+SymbolBody *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+                              uint64_t Size, InputSectionBase *Section);
+
+// Linker generated sections which can be used as inputs.
+struct InX {
+  static InputSection *ARMAttributes;
+  static BssSection *Bss;
+  static BssSection *BssRelRo;
+  static BuildIdSection *BuildId;
+  static InputSection *Common;
+  static SyntheticSection *Dynamic;
+  static StringTableSection *DynStrTab;
+  static SymbolTableBaseSection *DynSymTab;
+  static GnuHashTableSection *GnuHashTab;
+  static InputSection *Interp;
+  static GdbIndexSection *GdbIndex;
+  static GotSection *Got;
+  static GotPltSection *GotPlt;
+  static IgotPltSection *IgotPlt;
+  static MipsGotSection *MipsGot;
+  static MipsRldMapSection *MipsRldMap;
+  static PltSection *Plt;
+  static PltSection *Iplt;
+  static StringTableSection *ShStrTab;
+  static StringTableSection *StrTab;
+  static SymbolTableBaseSection *SymTab;
+};
+
+template <class ELFT> struct In : public InX {
+  static EhFrameHeader<ELFT> *EhFrameHdr;
+  static EhFrameSection<ELFT> *EhFrame;
+  static HashTableSection<ELFT> *HashTab;
+  static RelocationSection<ELFT> *RelaDyn;
+  static RelocationSection<ELFT> *RelaPlt;
+  static RelocationSection<ELFT> *RelaIplt;
+  static VersionDefinitionSection<ELFT> *VerDef;
+  static VersionTableSection<ELFT> *VerSym;
+  static VersionNeedSection<ELFT> *VerNeed;
+};
+
+template <class ELFT> EhFrameHeader<ELFT> *In<ELFT>::EhFrameHdr;
+template <class ELFT> EhFrameSection<ELFT> *In<ELFT>::EhFrame;
+template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab;
+template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn;
+template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt;
+template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt;
+template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef;
+template <class ELFT> VersionTableSection<ELFT> *In<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *In<ELFT>::VerNeed;
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
new file mode 100644 (file)
index 0000000..11986ef
--- /dev/null
@@ -0,0 +1,167 @@
+//===- Target.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Machine-specific things, such as applying relocations, creation of
+// GOT or PLT entries, etc., are handled in this file.
+//
+// Refer the ELF spec for the single letter variables, S, A or P, used
+// in this file.
+//
+// Some functions defined in this file has "relaxTls" as part of their names.
+// They do peephole optimization for TLS variables by rewriting instructions.
+// They are not part of the ABI but optional optimization, so you can skip
+// them if you are not interested in how TLS variables are optimized.
+// See the following paper for the details.
+//
+//   Ulrich Drepper, ELF Handling For Thread-Local Storage
+//   http://www.akkadia.org/drepper/tls.pdf
+//
+//===----------------------------------------------------------------------===//
+
+#include "Target.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "llvm/Object/ELF.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+TargetInfo *elf::Target;
+
+std::string lld::toString(uint32_t Type) {
+  StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type);
+  if (S == "Unknown")
+    return ("Unknown (" + Twine(Type) + ")").str();
+  return S;
+}
+
+TargetInfo *elf::getTarget() {
+  switch (Config->EMachine) {
+  case EM_386:
+  case EM_IAMCU:
+    return getX86TargetInfo();
+  case EM_AARCH64:
+    return getAArch64TargetInfo();
+  case EM_AMDGPU:
+    return getAMDGPUTargetInfo();
+  case EM_ARM:
+    return getARMTargetInfo();
+  case EM_AVR:
+    return getAVRTargetInfo();
+  case EM_MIPS:
+    switch (Config->EKind) {
+    case ELF32LEKind:
+      return getMipsTargetInfo<ELF32LE>();
+    case ELF32BEKind:
+      return getMipsTargetInfo<ELF32BE>();
+    case ELF64LEKind:
+      return getMipsTargetInfo<ELF64LE>();
+    case ELF64BEKind:
+      return getMipsTargetInfo<ELF64BE>();
+    default:
+      fatal("unsupported MIPS target");
+    }
+  case EM_PPC:
+    return getPPCTargetInfo();
+  case EM_PPC64:
+    return getPPC64TargetInfo();
+  case EM_SPARCV9:
+    return getSPARCV9TargetInfo();
+  case EM_X86_64:
+    if (Config->EKind == ELF32LEKind)
+      return getX32TargetInfo();
+    return getX86_64TargetInfo();
+  }
+  fatal("unknown target machine");
+}
+
+template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
+  for (InputSectionBase *D : InputSections) {
+    auto *IS = dyn_cast_or_null<InputSection>(D);
+    if (!IS || !IS->getParent())
+      continue;
+
+    uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
+    if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
+      return IS->template getLocation<ELFT>(Loc - ISLoc) + ": ";
+  }
+  return "";
+}
+
+std::string elf::getErrorLocation(const uint8_t *Loc) {
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    return getErrorLoc<ELF32LE>(Loc);
+  case ELF32BEKind:
+    return getErrorLoc<ELF32BE>(Loc);
+  case ELF64LEKind:
+    return getErrorLoc<ELF64LE>(Loc);
+  case ELF64BEKind:
+    return getErrorLoc<ELF64BE>(Loc);
+  default:
+    llvm_unreachable("unknown ELF type");
+  }
+}
+
+TargetInfo::~TargetInfo() {}
+
+int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
+  return 0;
+}
+
+bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
+
+bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
+                            const InputFile *File, const SymbolBody &S) const {
+  return false;
+}
+
+bool TargetInfo::inBranchRange(uint32_t RelocType, uint64_t Src,
+                               uint64_t Dst) const {
+  return true;
+}
+
+void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+  writeGotPlt(Buf, S);
+}
+
+RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                                    RelExpr Expr) const {
+  return Expr;
+}
+
+void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
+  llvm_unreachable("Should not have claimed to be relaxable");
+}
diff --git a/ELF/Target.h b/ELF/Target.h
new file mode 100644 (file)
index 0000000..1658a81
--- /dev/null
@@ -0,0 +1,162 @@
+//===- Target.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_TARGET_H
+#define LLD_ELF_TARGET_H
+
+#include "Error.h"
+#include "InputSection.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+std::string toString(uint32_t RelType);
+
+namespace elf {
+class InputFile;
+class SymbolBody;
+
+class TargetInfo {
+public:
+  virtual bool isPicRel(uint32_t Type) const { return true; }
+  virtual uint32_t getDynRel(uint32_t Type) const { return Type; }
+  virtual void writeGotPltHeader(uint8_t *Buf) const {}
+  virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {};
+  virtual void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const;
+  virtual int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
+
+  // If lazy binding is supported, the first entry of the PLT has code
+  // to call the dynamic linker to resolve PLT entries the first time
+  // they are called. This function writes that code.
+  virtual void writePltHeader(uint8_t *Buf) const {}
+
+  virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+                        uint64_t PltEntryAddr, int32_t Index,
+                        unsigned RelOff) const {}
+  virtual void addPltHeaderSymbols(InputSectionBase *IS) const {}
+  virtual void addPltSymbols(InputSectionBase *IS, uint64_t Off) const {}
+  // Returns true if a relocation only uses the low bits of a value such that
+  // all those bits are in in the same page. For example, if the relocation
+  // only uses the low 12 bits in a system with 4k pages. If this is true, the
+  // bits will always have the same value at runtime and we don't have to emit
+  // a dynamic relocation.
+  virtual bool usesOnlyLowPageBits(uint32_t Type) const;
+
+  // Decide whether a Thunk is needed for the relocation from File
+  // targeting S.
+  virtual bool needsThunk(RelExpr Expr, uint32_t RelocType,
+                          const InputFile *File, const SymbolBody &S) const;
+  // Return true if we can reach Dst from Src with Relocation RelocType
+  virtual bool inBranchRange(uint32_t RelocType, uint64_t Src,
+                             uint64_t Dst) const;
+  virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+                             const uint8_t *Loc) const = 0;
+  virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
+  virtual ~TargetInfo();
+
+  unsigned TlsGdRelaxSkip = 1;
+  unsigned PageSize = 4096;
+  unsigned DefaultMaxPageSize = 4096;
+
+  // On FreeBSD x86_64 the first page cannot be mmaped.
+  // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64
+  // installs that is 65536, so the first 15 pages cannot be used.
+  // Given that, the smallest value that can be used in here is 0x10000.
+  uint64_t DefaultImageBase = 0x10000;
+
+  // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for
+  // end of .got
+  uint64_t GotBaseSymOff = 0;
+
+  uint32_t CopyRel;
+  uint32_t GotRel;
+  uint32_t PltRel;
+  uint32_t RelativeRel;
+  uint32_t IRelativeRel;
+  uint32_t TlsDescRel;
+  uint32_t TlsGotRel;
+  uint32_t TlsModuleIndexRel;
+  uint32_t TlsOffsetRel;
+  unsigned GotEntrySize = 0;
+  unsigned GotPltEntrySize = 0;
+  unsigned PltEntrySize;
+  unsigned PltHeaderSize;
+
+  // At least on x86_64 positions 1 and 2 are used by the first plt entry
+  // to support lazy loading.
+  unsigned GotPltHeaderEntriesNum = 3;
+
+  // Set to 0 for variant 2
+  unsigned TcbSize = 0;
+
+  bool NeedsThunks = false;
+
+  // A 4-byte field corresponding to one or more trap instructions, used to pad
+  // executable OutputSections.
+  uint32_t TrapInstr = 0;
+
+  virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+                                  RelExpr Expr) const;
+  virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
+  virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+};
+
+TargetInfo *getAArch64TargetInfo();
+TargetInfo *getAMDGPUTargetInfo();
+TargetInfo *getARMTargetInfo();
+TargetInfo *getAVRTargetInfo();
+TargetInfo *getPPC64TargetInfo();
+TargetInfo *getPPCTargetInfo();
+TargetInfo *getSPARCV9TargetInfo();
+TargetInfo *getX32TargetInfo();
+TargetInfo *getX86TargetInfo();
+TargetInfo *getX86_64TargetInfo();
+template <class ELFT> TargetInfo *getMipsTargetInfo();
+
+std::string getErrorLocation(const uint8_t *Loc);
+
+uint64_t getPPC64TocBase();
+uint64_t getAArch64Page(uint64_t Expr);
+
+extern TargetInfo *Target;
+TargetInfo *getTarget();
+
+template <unsigned N>
+static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) {
+  if (!llvm::isInt<N>(V))
+    error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
+          " out of range");
+}
+
+template <unsigned N>
+static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
+  if (!llvm::isUInt<N>(V))
+    error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
+          " out of range");
+}
+
+template <unsigned N>
+static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
+  if (!llvm::isInt<N>(V) && !llvm::isUInt<N>(V))
+    error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
+          " out of range");
+}
+
+template <unsigned N>
+static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) {
+  if ((V & (N - 1)) != 0)
+    error(getErrorLocation(Loc) + "improper alignment for relocation " +
+          lld::toString(Type));
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Threads.h b/ELF/Threads.h
new file mode 100644 (file)
index 0000000..9feb868
--- /dev/null
@@ -0,0 +1,88 @@
+//===- Threads.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LLD supports threads to distribute workloads to multiple cores. Using
+// multicore is most effective when more than one core are idle. At the
+// last step of a build, it is often the case that a linker is the only
+// active process on a computer. So, we are naturally interested in using
+// threads wisely to reduce latency to deliver results to users.
+//
+// That said, we don't want to do "too clever" things using threads.
+// Complex multi-threaded algorithms are sometimes extremely hard to
+// reason about and can easily mess up the entire design.
+//
+// Fortunately, when a linker links large programs (when the link time is
+// most critical), it spends most of the time to work on massive number of
+// small pieces of data of the same kind, and there are opportunities for
+// large parallelism there. Here are examples:
+//
+//  - We have hundreds of thousands of input sections that need to be
+//    copied to a result file at the last step of link. Once we fix a file
+//    layout, each section can be copied to its destination and its
+//    relocations can be applied independently.
+//
+//  - We have tens of millions of small strings when constructing a
+//    mergeable string section.
+//
+// For the cases such as the former, we can just use parallel_for_each
+// instead of std::for_each (or a plain for loop). Because tasks are
+// completely independent from each other, we can run them in parallel
+// without any coordination between them. That's very easy to understand
+// and reason about.
+//
+// For the cases such as the latter, we can use parallel algorithms to
+// deal with massive data. We have to write code for a tailored algorithm
+// for each problem, but the complexity of multi-threading is isolated in
+// a single pass and doesn't affect the linker's overall design.
+//
+// The above approach seems to be working fairly well. As an example, when
+// linking Chromium (output size 1.6 GB), using 4 cores reduces latency to
+// 75% compared to single core (from 12.66 seconds to 9.55 seconds) on my
+// Ivy Bridge Xeon 2.8 GHz machine. Using 40 cores reduces it to 63% (from
+// 12.66 seconds to 7.95 seconds). Because of the Amdahl's law, the
+// speedup is not linear, but as you add more cores, it gets faster.
+//
+// On a final note, if you are trying to optimize, keep the axiom "don't
+// guess, measure!" in mind. Some important passes of the linker are not
+// that slow. For example, resolving all symbols is not a very heavy pass,
+// although it would be very hard to parallelize it. You want to first
+// identify a slow pass and then optimize it.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_THREADS_H
+#define LLD_ELF_THREADS_H
+
+#include "Config.h"
+
+#include "llvm/Support/Parallel.h"
+#include <functional>
+
+namespace lld {
+namespace elf {
+
+template <class IterTy, class FuncTy>
+void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) {
+  if (Config->Threads)
+    for_each(llvm::parallel::par, Begin, End, Fn);
+  else
+    for_each(llvm::parallel::seq, Begin, End, Fn);
+}
+
+inline void parallelForEachN(size_t Begin, size_t End,
+                             std::function<void(size_t)> Fn) {
+  if (Config->Threads)
+    for_each_n(llvm::parallel::par, Begin, End, Fn);
+  else
+    for_each_n(llvm::parallel::seq, Begin, End, Fn);
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
new file mode 100644 (file)
index 0000000..07289d0
--- /dev/null
@@ -0,0 +1,273 @@
+//===- Thunks.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file contains Thunk subclasses.
+//
+// A thunk is a small piece of code written after an input section
+// which is used to jump between "incompatible" functions
+// such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions.
+//
+// If a jump target is too far and its address doesn't fit to a
+// short jump instruction, we need to create a thunk too, but we
+// haven't supported it yet.
+//
+// i386 and x86-64 don't need thunks.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Thunks.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputSection.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+
+namespace lld {
+namespace elf {
+
+namespace {
+
+// Specific ARM Thunk implementations. The naming convention is:
+// Source State, TargetState, Target Requirement, ABS or PI, Range
+class ARMV7ABSLongThunk final : public Thunk {
+public:
+  ARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {}
+
+  uint32_t size() const override { return 12; }
+  void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+  void addSymbols(ThunkSection &IS) override;
+  bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+class ARMV7PILongThunk final : public Thunk {
+public:
+  ARMV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {}
+
+  uint32_t size() const override { return 16; }
+  void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+  void addSymbols(ThunkSection &IS) override;
+  bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+class ThumbV7ABSLongThunk final : public Thunk {
+public:
+  ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; }
+
+  uint32_t size() const override { return 10; }
+  void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+  void addSymbols(ThunkSection &IS) override;
+  bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+class ThumbV7PILongThunk final : public Thunk {
+public:
+  ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; }
+
+  uint32_t size() const override { return 12; }
+  void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+  void addSymbols(ThunkSection &IS) override;
+  bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+// MIPS LA25 thunk
+class MipsThunk final : public Thunk {
+public:
+  MipsThunk(const SymbolBody &Dest) : Thunk(Dest) {}
+
+  uint32_t size() const override { return 16; }
+  void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+  void addSymbols(ThunkSection &IS) override;
+  InputSection *getTargetInputSection() const override;
+};
+
+} // end anonymous namespace
+
+// ARM Target Thunks
+static uint64_t getARMThunkDestVA(const SymbolBody &S) {
+  uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA();
+  return SignExtend64<32>(V);
+}
+
+void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+  const uint8_t Data[] = {
+      0x00, 0xc0, 0x00, 0xe3, // movw         ip,:lower16:S
+      0x00, 0xc0, 0x40, 0xe3, // movt         ip,:upper16:S
+      0x1c, 0xff, 0x2f, 0xe1, // bx   ip
+  };
+  uint64_t S = getARMThunkDestVA(Destination);
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S);
+  Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S);
+}
+
+void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
+  ThunkSym = addSyntheticLocal(
+      Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
+      Offset, size(), &IS);
+  addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+  // Thumb branch relocations can't use BLX
+  return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+  const uint8_t Data[] = {
+      0x40, 0xf2, 0x00, 0x0c, // movw         ip, :lower16:S
+      0xc0, 0xf2, 0x00, 0x0c, // movt         ip, :upper16:S
+      0x60, 0x47,             // bx   ip
+  };
+  uint64_t S = getARMThunkDestVA(Destination);
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S);
+  Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S);
+}
+
+void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
+  ThunkSym = addSyntheticLocal(
+      Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
+      Offset | 0x1, size(), &IS);
+  addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+  // ARM branch relocations can't use BLX
+  return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
+         RelocType != R_ARM_PLT32;
+}
+
+void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+  const uint8_t Data[] = {
+      0xf0, 0xcf, 0x0f, 0xe3, // P:  movw ip,:lower16:S - (P + (L1-P) +8)
+      0x00, 0xc0, 0x40, 0xe3, //     movt ip,:upper16:S - (P + (L1-P+4) +8)
+      0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+      0x1c, 0xff, 0x2f, 0xe1, //     bx r12
+  };
+  uint64_t S = getARMThunkDestVA(Destination);
+  uint64_t P = ThunkSym->getVA();
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
+  Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
+}
+
+void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
+  ThunkSym = addSyntheticLocal(
+      Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
+      Offset, size(), &IS);
+  addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+  // Thumb branch relocations can't use BLX
+  return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
+  const uint8_t Data[] = {
+      0x4f, 0xf6, 0xf4, 0x7c, // P:  movw ip,:lower16:S - (P + (L1-P) + 4)
+      0xc0, 0xf2, 0x00, 0x0c, //     movt ip,:upper16:S - (P + (L1-P+4) + 4)
+      0xfc, 0x44,             // L1: add  r12, pc
+      0x60, 0x47,             //     bx   r12
+  };
+  uint64_t S = getARMThunkDestVA(Destination);
+  uint64_t P = ThunkSym->getVA() & ~0x1;
+  memcpy(Buf, Data, sizeof(Data));
+  Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
+  Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
+}
+
+void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
+  ThunkSym = addSyntheticLocal(
+      Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC,
+      Offset | 0x1, size(), &IS);
+  addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+  // ARM branch relocations can't use BLX
+  return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
+         RelocType != R_ARM_PLT32;
+}
+
+// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
+void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+  uint64_t S = Destination.getVA();
+  write32(Buf, 0x3c190000, Config->Endianness); // lui   $25, %hi(func)
+  write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j     func
+  write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func)
+  write32(Buf + 12, 0x00000000, Config->Endianness); // nop
+  Target->relocateOne(Buf, R_MIPS_HI16, S);
+  Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
+}
+
+void MipsThunk::addSymbols(ThunkSection &IS) {
+  ThunkSym =
+      addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()),
+                        STT_FUNC, Offset, size(), &IS);
+}
+
+InputSection *MipsThunk::getTargetInputSection() const {
+  auto *DR = dyn_cast<DefinedRegular>(&Destination);
+  return dyn_cast<InputSection>(DR->Section);
+}
+
+Thunk::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {}
+
+Thunk::~Thunk() = default;
+
+// Creates a thunk for Thumb-ARM interworking.
+static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) {
+  // ARM relocations need ARM to Thumb interworking Thunks.
+  // Thumb relocations need Thumb to ARM relocations.
+  // Use position independent Thunks if we require position independent code.
+  switch (Reloc) {
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+  case R_ARM_JUMP24:
+    if (Config->Pic)
+      return make<ARMV7PILongThunk>(S);
+    return make<ARMV7ABSLongThunk>(S);
+  case R_ARM_THM_JUMP19:
+  case R_ARM_THM_JUMP24:
+    if (Config->Pic)
+      return make<ThumbV7PILongThunk>(S);
+    return make<ThumbV7ABSLongThunk>(S);
+  }
+  fatal("unrecognized relocation type");
+}
+
+static Thunk *addThunkMips(SymbolBody &S) { return make<MipsThunk>(S); }
+
+Thunk *addThunk(uint32_t RelocType, SymbolBody &S) {
+  if (Config->EMachine == EM_ARM)
+    return addThunkArm(RelocType, S);
+  else if (Config->EMachine == EM_MIPS)
+    return addThunkMips(S);
+  llvm_unreachable("add Thunk only supported for ARM and Mips");
+  return nullptr;
+}
+
+} // end namespace elf
+} // end namespace lld
diff --git a/ELF/Thunks.h b/ELF/Thunks.h
new file mode 100644 (file)
index 0000000..21eba69
--- /dev/null
@@ -0,0 +1,63 @@
+//===- Thunks.h --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_THUNKS_H
+#define LLD_ELF_THUNKS_H
+
+#include "Relocations.h"
+
+namespace lld {
+namespace elf {
+class SymbolBody;
+class ThunkSection;
+// Class to describe an instance of a Thunk.
+// A Thunk is a code-sequence inserted by the linker in between a caller and
+// the callee. The relocation to the callee is redirected to the Thunk, which
+// after executing transfers control to the callee. Typical uses of Thunks
+// include transferring control from non-pi to pi and changing state on
+// targets like ARM.
+//
+// Thunks can be created for DefinedRegular, Shared and Undefined Symbols.
+// Thunks are assigned to synthetic ThunkSections
+class Thunk {
+public:
+  Thunk(const SymbolBody &Destination);
+  virtual ~Thunk();
+
+  virtual uint32_t size() const { return 0; }
+  virtual void writeTo(uint8_t *Buf, ThunkSection &IS) const {}
+
+  // All Thunks must define at least one symbol ThunkSym so that we can
+  // redirect relocations to it.
+  virtual void addSymbols(ThunkSection &IS) {}
+
+  // Some Thunks must be placed immediately before their Target as they elide
+  // a branch and fall through to the first Symbol in the Target.
+  virtual InputSection *getTargetInputSection() const { return nullptr; }
+
+  // To reuse a Thunk the caller as identified by the RelocType must be
+  // compatible with it.
+  virtual bool isCompatibleWith(uint32_t RelocType) const { return true; }
+
+  // The alignment requirement for this Thunk, defaults to the size of the
+  // typical code section alignment.
+  const SymbolBody &Destination;
+  SymbolBody *ThunkSym;
+  uint64_t Offset;
+  uint32_t Alignment = 4;
+};
+
+// For a Relocation to symbol S create a Thunk to be added to a synthetic
+// ThunkSection. At present there are implementations for ARM and Mips Thunks.
+Thunk *addThunk(uint32_t RelocType, SymbolBody &S);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
new file mode 100644 (file)
index 0000000..1853f99
--- /dev/null
@@ -0,0 +1,1913 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Writer.h"
+#include "Config.h"
+#include "Filesystem.h"
+#include "LinkerScript.h"
+#include "MapFile.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Relocations.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Threads.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <climits>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+// The writer writes a SymbolTable result to a file.
+template <class ELFT> class Writer {
+public:
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Ehdr Elf_Ehdr;
+  typedef typename ELFT::Phdr Elf_Phdr;
+
+  void run();
+
+private:
+  void clearOutputSections();
+  void createSyntheticSections();
+  void copyLocalSymbols();
+  void addSectionSymbols();
+  void addReservedSymbols();
+  void createSections();
+  void forEachRelSec(std::function<void(InputSectionBase &)> Fn);
+  void sortSections();
+  void finalizeSections();
+  void addPredefinedSections();
+
+  std::vector<PhdrEntry> createPhdrs();
+  void removeEmptyPTLoad();
+  void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
+  void assignFileOffsets();
+  void assignFileOffsetsBinary();
+  void setPhdrs();
+  void fixSectionAlignments();
+  void fixPredefinedSymbols();
+  void openFile();
+  void writeHeader();
+  void writeSections();
+  void writeSectionsBinary();
+  void writeBuildId();
+
+  std::unique_ptr<FileOutputBuffer> Buffer;
+
+  OutputSectionFactory Factory;
+
+  void addRelIpltSymbols();
+  void addStartEndSymbols();
+  void addStartStopSymbols(OutputSection *Sec);
+  uint64_t getEntryAddr();
+  OutputSection *findSectionInScript(StringRef Name);
+  OutputSectionCommand *findSectionCommand(StringRef Name);
+
+  std::vector<PhdrEntry> Phdrs;
+
+  uint64_t FileSize;
+  uint64_t SectionHeaderOff;
+
+  bool HasGotBaseSym = false;
+};
+} // anonymous namespace
+
+StringRef elf::getOutputSectionName(StringRef Name) {
+  // ".zdebug_" is a prefix for ZLIB-compressed sections.
+  // Because we decompressed input sections, we want to remove 'z'.
+  if (Name.startswith(".zdebug_"))
+    return Saver.save("." + Name.substr(2));
+
+  if (Config->Relocatable)
+    return Name;
+
+  for (StringRef V :
+       {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
+        ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
+        ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
+    StringRef Prefix = V.drop_back();
+    if (Name.startswith(V) || Name == Prefix)
+      return Prefix;
+  }
+
+  // CommonSection is identified as "COMMON" in linker scripts.
+  // By default, it should go to .bss section.
+  if (Name == "COMMON")
+    return ".bss";
+
+  return Name;
+}
+
+template <class ELFT> static bool needsInterpSection() {
+  return !Symtab<ELFT>::X->getSharedFiles().empty() &&
+         !Config->DynamicLinker.empty() && !Script->ignoreInterpSection();
+}
+
+template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); }
+
+template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
+  auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const PhdrEntry &P) {
+    if (P.p_type != PT_LOAD)
+      return false;
+    if (!P.First)
+      return true;
+    uint64_t Size = P.Last->Addr + P.Last->Size - P.First->Addr;
+    return Size == 0;
+  });
+  Phdrs.erase(I, Phdrs.end());
+}
+
+template <class ELFT> static void combineEhFrameSections() {
+  for (InputSectionBase *&S : InputSections) {
+    EhInputSection *ES = dyn_cast<EhInputSection>(S);
+    if (!ES || !ES->Live)
+      continue;
+
+    In<ELFT>::EhFrame->addSection(ES);
+    S = nullptr;
+  }
+
+  std::vector<InputSectionBase *> &V = InputSections;
+  V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
+}
+
+template <class ELFT> void Writer<ELFT>::clearOutputSections() {
+  // Clear the OutputSections to make sure it is not used anymore. Any
+  // code from this point on should be using the linker script
+  // commands.
+  for (OutputSection *Sec : OutputSections)
+    Sec->Sections.clear();
+  OutputSections.clear();
+}
+
+// The main function of the writer.
+template <class ELFT> void Writer<ELFT>::run() {
+  // Create linker-synthesized sections such as .got or .plt.
+  // Such sections are of type input section.
+  createSyntheticSections();
+
+  if (!Config->Relocatable)
+    combineEhFrameSections<ELFT>();
+
+  // We need to create some reserved symbols such as _end. Create them.
+  if (!Config->Relocatable)
+    addReservedSymbols();
+
+  // Create output sections.
+  if (Script->Opt.HasSections) {
+    // If linker script contains SECTIONS commands, let it create sections.
+    Script->processCommands(Factory);
+
+    // Linker scripts may have left some input sections unassigned.
+    // Assign such sections using the default rule.
+    Script->addOrphanSections(Factory);
+  } else {
+    // If linker script does not contain SECTIONS commands, create
+    // output sections by default rules. We still need to give the
+    // linker script a chance to run, because it might contain
+    // non-SECTIONS commands such as ASSERT.
+    Script->processCommands(Factory);
+    createSections();
+  }
+  clearOutputSections();
+
+  if (Config->Discard != DiscardPolicy::All)
+    copyLocalSymbols();
+
+  if (Config->CopyRelocs)
+    addSectionSymbols();
+
+  // Now that we have a complete set of output sections. This function
+  // completes section contents. For example, we need to add strings
+  // to the string table, and add entries to .got and .plt.
+  // finalizeSections does that.
+  finalizeSections();
+  if (ErrorCount)
+    return;
+
+  if (!Script->Opt.HasSections && !Config->Relocatable)
+    fixSectionAlignments();
+
+  // If -compressed-debug-sections is specified, we need to compress
+  // .debug_* sections. Do it right now because it changes the size of
+  // output sections.
+  parallelForEach(
+      OutputSectionCommands.begin(), OutputSectionCommands.end(),
+      [](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); });
+
+  Script->assignAddresses();
+  Script->allocateHeaders(Phdrs);
+
+  // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
+  // 0 sized region. This has to be done late since only after assignAddresses
+  // we know the size of the sections.
+  removeEmptyPTLoad();
+
+  if (!Config->OFormatBinary)
+    assignFileOffsets();
+  else
+    assignFileOffsetsBinary();
+
+  setPhdrs();
+
+  if (Config->Relocatable) {
+    for (OutputSectionCommand *Cmd : OutputSectionCommands)
+      Cmd->Sec->Addr = 0;
+  } else {
+    fixPredefinedSymbols();
+  }
+
+  // It does not make sense try to open the file if we have error already.
+  if (ErrorCount)
+    return;
+  // Write the result down to a file.
+  openFile();
+  if (ErrorCount)
+    return;
+
+  if (!Config->OFormatBinary) {
+    writeHeader();
+    writeSections();
+  } else {
+    writeSectionsBinary();
+  }
+
+  // Backfill .note.gnu.build-id section content. This is done at last
+  // because the content is usually a hash value of the entire output file.
+  writeBuildId();
+  if (ErrorCount)
+    return;
+
+  // Handle -Map option.
+  writeMapFile<ELFT>(OutputSectionCommands);
+  if (ErrorCount)
+    return;
+
+  if (auto EC = Buffer->commit())
+    error("failed to write to the output file: " + EC.message());
+
+  // Flush the output streams and exit immediately. A full shutdown
+  // is a good test that we are keeping track of all allocated memory,
+  // but actually freeing it is a waste of time in a regular linker run.
+  if (Config->ExitEarly)
+    exitLld(0);
+}
+
+// Initialize Out members.
+template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
+  // Initialize all pointers with NULL. This is needed because
+  // you can call lld::elf::main more than once as a library.
+  memset(&Out::First, 0, sizeof(Out));
+
+  auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
+
+  InX::DynStrTab = make<StringTableSection>(".dynstr", true);
+  InX::Dynamic = make<DynamicSection<ELFT>>();
+  In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
+      Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
+  InX::ShStrTab = make<StringTableSection>(".shstrtab", false);
+
+  Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
+  Out::ElfHeader->Size = sizeof(Elf_Ehdr);
+  Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
+  Out::ProgramHeaders->updateAlignment(Config->Wordsize);
+
+  if (needsInterpSection<ELFT>()) {
+    InX::Interp = createInterpSection();
+    Add(InX::Interp);
+  } else {
+    InX::Interp = nullptr;
+  }
+
+  if (Config->Strip != StripPolicy::All) {
+    InX::StrTab = make<StringTableSection>(".strtab", false);
+    InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
+  }
+
+  if (Config->BuildId != BuildIdKind::None) {
+    InX::BuildId = make<BuildIdSection>();
+    Add(InX::BuildId);
+  }
+
+  InX::Common = createCommonSection<ELFT>();
+  if (InX::Common)
+    Add(InX::Common);
+
+  InX::Bss = make<BssSection>(".bss");
+  Add(InX::Bss);
+  InX::BssRelRo = make<BssSection>(".bss.rel.ro");
+  Add(InX::BssRelRo);
+
+  // Add MIPS-specific sections.
+  bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() ||
+                      Config->Pic || Config->ExportDynamic;
+  if (Config->EMachine == EM_MIPS) {
+    if (!Config->Shared && HasDynSymTab) {
+      InX::MipsRldMap = make<MipsRldMapSection>();
+      Add(InX::MipsRldMap);
+    }
+    if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
+      Add(Sec);
+    if (auto *Sec = MipsOptionsSection<ELFT>::create())
+      Add(Sec);
+    if (auto *Sec = MipsReginfoSection<ELFT>::create())
+      Add(Sec);
+  }
+
+  if (HasDynSymTab) {
+    InX::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab);
+    Add(InX::DynSymTab);
+
+    In<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
+    Add(In<ELFT>::VerSym);
+
+    if (!Config->VersionDefinitions.empty()) {
+      In<ELFT>::VerDef = make<VersionDefinitionSection<ELFT>>();
+      Add(In<ELFT>::VerDef);
+    }
+
+    In<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
+    Add(In<ELFT>::VerNeed);
+
+    if (Config->GnuHash) {
+      InX::GnuHashTab = make<GnuHashTableSection>();
+      Add(InX::GnuHashTab);
+    }
+
+    if (Config->SysvHash) {
+      In<ELFT>::HashTab = make<HashTableSection<ELFT>>();
+      Add(In<ELFT>::HashTab);
+    }
+
+    Add(InX::Dynamic);
+    Add(InX::DynStrTab);
+    Add(In<ELFT>::RelaDyn);
+  }
+
+  // Add .got. MIPS' .got is so different from the other archs,
+  // it has its own class.
+  if (Config->EMachine == EM_MIPS) {
+    InX::MipsGot = make<MipsGotSection>();
+    Add(InX::MipsGot);
+  } else {
+    InX::Got = make<GotSection>();
+    Add(InX::Got);
+  }
+
+  InX::GotPlt = make<GotPltSection>();
+  Add(InX::GotPlt);
+  InX::IgotPlt = make<IgotPltSection>();
+  Add(InX::IgotPlt);
+
+  if (Config->GdbIndex) {
+    InX::GdbIndex = createGdbIndex<ELFT>();
+    Add(InX::GdbIndex);
+  }
+
+  // We always need to add rel[a].plt to output if it has entries.
+  // Even for static linking it can contain R_[*]_IRELATIVE relocations.
+  In<ELFT>::RelaPlt = make<RelocationSection<ELFT>>(
+      Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
+  Add(In<ELFT>::RelaPlt);
+
+  // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
+  // that the IRelative relocations are processed last by the dynamic loader
+  In<ELFT>::RelaIplt = make<RelocationSection<ELFT>>(
+      (Config->EMachine == EM_ARM) ? ".rel.dyn" : In<ELFT>::RelaPlt->Name,
+      false /*Sort*/);
+  Add(In<ELFT>::RelaIplt);
+
+  InX::Plt = make<PltSection>(Target->PltHeaderSize);
+  Add(InX::Plt);
+  InX::Iplt = make<PltSection>(0);
+  Add(InX::Iplt);
+
+  if (!Config->Relocatable) {
+    if (Config->EhFrameHdr) {
+      In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
+      Add(In<ELFT>::EhFrameHdr);
+    }
+    In<ELFT>::EhFrame = make<EhFrameSection<ELFT>>();
+    Add(In<ELFT>::EhFrame);
+  }
+
+  if (InX::SymTab)
+    Add(InX::SymTab);
+  Add(InX::ShStrTab);
+  if (InX::StrTab)
+    Add(InX::StrTab);
+}
+
+static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
+                               const SymbolBody &B) {
+  if (B.isFile() || B.isSection())
+    return false;
+
+  // If sym references a section in a discarded group, don't keep it.
+  if (Sec == &InputSection::Discarded)
+    return false;
+
+  if (Config->Discard == DiscardPolicy::None)
+    return true;
+
+  // In ELF assembly .L symbols are normally discarded by the assembler.
+  // If the assembler fails to do so, the linker discards them if
+  // * --discard-locals is used.
+  // * The symbol is in a SHF_MERGE section, which is normally the reason for
+  //   the assembler keeping the .L symbol.
+  if (!SymName.startswith(".L") && !SymName.empty())
+    return true;
+
+  if (Config->Discard == DiscardPolicy::Locals)
+    return false;
+
+  return !Sec || !(Sec->Flags & SHF_MERGE);
+}
+
+static bool includeInSymtab(const SymbolBody &B) {
+  if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj)
+    return false;
+
+  if (auto *D = dyn_cast<DefinedRegular>(&B)) {
+    // Always include absolute symbols.
+    SectionBase *Sec = D->Section;
+    if (!Sec)
+      return true;
+    if (auto *IS = dyn_cast<InputSectionBase>(Sec)) {
+      Sec = IS->Repl;
+      IS = cast<InputSectionBase>(Sec);
+      // Exclude symbols pointing to garbage-collected sections.
+      if (!IS->Live)
+        return false;
+    }
+    if (auto *S = dyn_cast<MergeInputSection>(Sec))
+      if (!S->getSectionPiece(D->Value)->Live)
+        return false;
+  }
+  return true;
+}
+
+// Local symbols are not in the linker's symbol table. This function scans
+// each object file's symbol table to copy local symbols to the output.
+template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
+  if (!InX::SymTab)
+    return;
+  for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) {
+    for (SymbolBody *B : F->getLocalSymbols()) {
+      if (!B->IsLocal)
+        fatal(toString(F) +
+              ": broken object: getLocalSymbols returns a non-local symbol");
+      auto *DR = dyn_cast<DefinedRegular>(B);
+
+      // No reason to keep local undefined symbol in symtab.
+      if (!DR)
+        continue;
+      if (!includeInSymtab(*B))
+        continue;
+
+      SectionBase *Sec = DR->Section;
+      if (!shouldKeepInSymtab(Sec, B->getName(), *B))
+        continue;
+      InX::SymTab->addSymbol(B);
+    }
+  }
+}
+
+template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
+  // Create one STT_SECTION symbol for each output section we might
+  // have a relocation with.
+  for (BaseCommand *Base : Script->Opt.Commands) {
+    auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+    if (!Cmd)
+      continue;
+    auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) {
+      if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+        return !ISD->Sections.empty();
+      return false;
+    });
+    if (I == Cmd->Commands.end())
+      continue;
+    InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0];
+    if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL ||
+        IS->Type == SHT_RELA)
+      continue;
+
+    auto *Sym =
+        make<DefinedRegular>("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION,
+                             /*Value=*/0, /*Size=*/0, IS, nullptr);
+    InX::SymTab->addSymbol(Sym);
+  }
+}
+
+// Today's loaders have a feature to make segments read-only after
+// processing dynamic relocations to enhance security. PT_GNU_RELRO
+// is defined for that.
+//
+// This function returns true if a section needs to be put into a
+// PT_GNU_RELRO segment.
+bool elf::isRelroSection(const OutputSection *Sec) {
+  if (!Config->ZRelro)
+    return false;
+
+  uint64_t Flags = Sec->Flags;
+
+  // Non-allocatable or non-writable sections don't need RELRO because
+  // they are not writable or not even mapped to memory in the first place.
+  // RELRO is for sections that are essentially read-only but need to
+  // be writable only at process startup to allow dynamic linker to
+  // apply relocations.
+  if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
+    return false;
+
+  // Once initialized, TLS data segments are used as data templates
+  // for a thread-local storage. For each new thread, runtime
+  // allocates memory for a TLS and copy templates there. No thread
+  // are supposed to use templates directly. Thus, it can be in RELRO.
+  if (Flags & SHF_TLS)
+    return true;
+
+  // .init_array, .preinit_array and .fini_array contain pointers to
+  // functions that are executed on process startup or exit. These
+  // pointers are set by the static linker, and they are not expected
+  // to change at runtime. But if you are an attacker, you could do
+  // interesting things by manipulating pointers in .fini_array, for
+  // example. So they are put into RELRO.
+  uint32_t Type = Sec->Type;
+  if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
+      Type == SHT_PREINIT_ARRAY)
+    return true;
+
+  // .got contains pointers to external symbols. They are resolved by
+  // the dynamic linker when a module is loaded into memory, and after
+  // that they are not expected to change. So, it can be in RELRO.
+  if (InX::Got && Sec == InX::Got->getParent())
+    return true;
+
+  // .got.plt contains pointers to external function symbols. They are
+  // by default resolved lazily, so we usually cannot put it into RELRO.
+  // However, if "-z now" is given, the lazy symbol resolution is
+  // disabled, which enables us to put it into RELRO.
+  if (Sec == InX::GotPlt->getParent())
+    return Config->ZNow;
+
+  // .dynamic section contains data for the dynamic linker, and
+  // there's no need to write to it at runtime, so it's better to put
+  // it into RELRO.
+  if (Sec == InX::Dynamic->getParent())
+    return true;
+
+  // .bss.rel.ro is used for copy relocations for read-only symbols.
+  // Since the dynamic linker needs to process copy relocations, the
+  // section cannot be read-only, but once initialized, they shouldn't
+  // change.
+  if (Sec == InX::BssRelRo->getParent())
+    return true;
+
+  // Sections with some special names are put into RELRO. This is a
+  // bit unfortunate because section names shouldn't be significant in
+  // ELF in spirit. But in reality many linker features depend on
+  // magic section names.
+  StringRef S = Sec->Name;
+  return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
+         S == ".eh_frame" || S == ".openbsd.randomdata";
+}
+
+// We compute a rank for each section. The rank indicates where the
+// section should be placed in the file.  Instead of using simple
+// numbers (0,1,2...), we use a series of flags. One for each decision
+// point when placing the section.
+// Using flags has two key properties:
+// * It is easy to check if a give branch was taken.
+// * It is easy two see how similar two ranks are (see getRankProximity).
+enum RankFlags {
+  RF_NOT_ADDR_SET = 1 << 16,
+  RF_NOT_INTERP = 1 << 15,
+  RF_NOT_ALLOC = 1 << 14,
+  RF_WRITE = 1 << 13,
+  RF_EXEC_WRITE = 1 << 12,
+  RF_EXEC = 1 << 11,
+  RF_NON_TLS_BSS = 1 << 10,
+  RF_NON_TLS_BSS_RO = 1 << 9,
+  RF_NOT_TLS = 1 << 8,
+  RF_BSS = 1 << 7,
+  RF_PPC_NOT_TOCBSS = 1 << 6,
+  RF_PPC_OPD = 1 << 5,
+  RF_PPC_TOCL = 1 << 4,
+  RF_PPC_TOC = 1 << 3,
+  RF_PPC_BRANCH_LT = 1 << 2,
+  RF_MIPS_GPREL = 1 << 1,
+  RF_MIPS_NOT_GOT = 1 << 0
+};
+
+static unsigned getSectionRank(const OutputSection *Sec) {
+  unsigned Rank = 0;
+
+  // We want to put section specified by -T option first, so we
+  // can start assigning VA starting from them later.
+  if (Config->SectionStartMap.count(Sec->Name))
+    return Rank;
+  Rank |= RF_NOT_ADDR_SET;
+
+  // Put .interp first because some loaders want to see that section
+  // on the first page of the executable file when loaded into memory.
+  if (Sec->Name == ".interp")
+    return Rank;
+  Rank |= RF_NOT_INTERP;
+
+  // Allocatable sections go first to reduce the total PT_LOAD size and
+  // so debug info doesn't change addresses in actual code.
+  if (!(Sec->Flags & SHF_ALLOC))
+    return Rank | RF_NOT_ALLOC;
+
+  // Sort sections based on their access permission in the following
+  // order: R, RX, RWX, RW.  This order is based on the following
+  // considerations:
+  // * Read-only sections come first such that they go in the
+  //   PT_LOAD covering the program headers at the start of the file.
+  // * Read-only, executable sections come next, unless the
+  //   -no-rosegment option is used.
+  // * Writable, executable sections follow such that .plt on
+  //   architectures where it needs to be writable will be placed
+  //   between .text and .data.
+  // * Writable sections come last, such that .bss lands at the very
+  //   end of the last PT_LOAD.
+  bool IsExec = Sec->Flags & SHF_EXECINSTR;
+  bool IsWrite = Sec->Flags & SHF_WRITE;
+
+  if (IsExec) {
+    if (IsWrite)
+      Rank |= RF_EXEC_WRITE;
+    else if (!Config->SingleRoRx)
+      Rank |= RF_EXEC;
+  } else {
+    if (IsWrite)
+      Rank |= RF_WRITE;
+  }
+
+  // If we got here we know that both A and B are in the same PT_LOAD.
+
+  bool IsTls = Sec->Flags & SHF_TLS;
+  bool IsNoBits = Sec->Type == SHT_NOBITS;
+
+  // The first requirement we have is to put (non-TLS) nobits sections last. The
+  // reason is that the only thing the dynamic linker will see about them is a
+  // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the
+  // PT_LOAD, so that has to correspond to the nobits sections.
+  bool IsNonTlsNoBits = IsNoBits && !IsTls;
+  if (IsNonTlsNoBits)
+    Rank |= RF_NON_TLS_BSS;
+
+  // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo
+  // sections after r/w ones, so that the RelRo sections are contiguous.
+  bool IsRelRo = isRelroSection(Sec);
+  if (IsNonTlsNoBits && !IsRelRo)
+    Rank |= RF_NON_TLS_BSS_RO;
+  if (!IsNonTlsNoBits && IsRelRo)
+    Rank |= RF_NON_TLS_BSS_RO;
+
+  // The TLS initialization block needs to be a single contiguous block in a R/W
+  // PT_LOAD, so stick TLS sections directly before the other RelRo R/W
+  // sections. The TLS NOBITS sections are placed here as they don't take up
+  // virtual address space in the PT_LOAD.
+  if (!IsTls)
+    Rank |= RF_NOT_TLS;
+
+  // Within the TLS initialization block, the non-nobits sections need to appear
+  // first.
+  if (IsNoBits)
+    Rank |= RF_BSS;
+
+  // // Some architectures have additional ordering restrictions for sections
+  // // within the same PT_LOAD.
+  if (Config->EMachine == EM_PPC64) {
+    // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections
+    // that we would like to make sure appear is a specific order to maximize
+    // their coverage by a single signed 16-bit offset from the TOC base
+    // pointer. Conversely, the special .tocbss section should be first among
+    // all SHT_NOBITS sections. This will put it next to the loaded special
+    // PPC64 sections (and, thus, within reach of the TOC base pointer).
+    StringRef Name = Sec->Name;
+    if (Name != ".tocbss")
+      Rank |= RF_PPC_NOT_TOCBSS;
+
+    if (Name == ".opd")
+      Rank |= RF_PPC_OPD;
+
+    if (Name == ".toc1")
+      Rank |= RF_PPC_TOCL;
+
+    if (Name == ".toc")
+      Rank |= RF_PPC_TOC;
+
+    if (Name == ".branch_lt")
+      Rank |= RF_PPC_BRANCH_LT;
+  }
+  if (Config->EMachine == EM_MIPS) {
+    // All sections with SHF_MIPS_GPREL flag should be grouped together
+    // because data in these sections is addressable with a gp relative address.
+    if (Sec->Flags & SHF_MIPS_GPREL)
+      Rank |= RF_MIPS_GPREL;
+
+    if (Sec->Name != ".got")
+      Rank |= RF_MIPS_NOT_GOT;
+  }
+
+  return Rank;
+}
+
+static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) {
+  const OutputSection *A = cast<OutputSectionCommand>(ACmd)->Sec;
+  const OutputSection *B = cast<OutputSectionCommand>(BCmd)->Sec;
+  if (A->SortRank != B->SortRank)
+    return A->SortRank < B->SortRank;
+  if (!(A->SortRank & RF_NOT_ADDR_SET))
+    return Config->SectionStartMap.lookup(A->Name) <
+           Config->SectionStartMap.lookup(B->Name);
+  return false;
+}
+
+void PhdrEntry::add(OutputSection *Sec) {
+  Last = Sec;
+  if (!First)
+    First = Sec;
+  p_align = std::max(p_align, Sec->Alignment);
+  if (p_type == PT_LOAD)
+    Sec->FirstInPtLoad = First;
+}
+
+template <class ELFT>
+static Symbol *addRegular(StringRef Name, SectionBase *Sec, uint64_t Value,
+                          uint8_t StOther = STV_HIDDEN,
+                          uint8_t Binding = STB_WEAK) {
+  // The linker generated symbols are added as STB_WEAK to allow user defined
+  // ones to override them.
+  return Symtab<ELFT>::X->addRegular(Name, StOther, STT_NOTYPE, Value,
+                                     /*Size=*/0, Binding, Sec,
+                                     /*File=*/nullptr);
+}
+
+template <class ELFT>
+static DefinedRegular *
+addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val,
+                   uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) {
+  SymbolBody *S = Symtab<ELFT>::X->find(Name);
+  if (!S)
+    return nullptr;
+  if (S->isInCurrentDSO())
+    return nullptr;
+  return cast<DefinedRegular>(
+      addRegular<ELFT>(Name, Sec, Val, StOther, Binding)->body());
+}
+
+// The beginning and the ending of .rel[a].plt section are marked
+// with __rel[a]_iplt_{start,end} symbols if it is a statically linked
+// executable. The runtime needs these symbols in order to resolve
+// all IRELATIVE relocs on startup. For dynamic executables, we don't
+// need these symbols, since IRELATIVE relocs are resolved through GOT
+// and PLT. For details, see http://www.airs.com/blog/archives/403.
+template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
+  if (InX::DynSymTab)
+    return;
+  StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
+  addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
+
+  S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
+  addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1, STV_HIDDEN, STB_WEAK);
+}
+
+// The linker is expected to define some symbols depending on
+// the linking result. This function defines such symbols.
+template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
+  if (Config->EMachine == EM_MIPS) {
+    // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
+    // so that it points to an absolute address which by default is relative
+    // to GOT. Default offset is 0x7ff0.
+    // See "Global Data Symbols" in Chapter 6 in the following document:
+    // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+    ElfSym::MipsGp = Symtab<ELFT>::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL);
+
+    // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
+    // start of function and 'gp' pointer into GOT.
+    if (Symtab<ELFT>::X->find("_gp_disp"))
+      ElfSym::MipsGpDisp =
+          Symtab<ELFT>::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL);
+
+    // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
+    // pointer. This symbol is used in the code generated by .cpload pseudo-op
+    // in case of using -mno-shared option.
+    // https://sourceware.org/ml/binutils/2004-12/msg00094.html
+    if (Symtab<ELFT>::X->find("__gnu_local_gp"))
+      ElfSym::MipsLocalGp =
+          Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL);
+  }
+
+  // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+  // be at some offset from the base of the .got section, usually 0 or the end
+  // of the .got
+  InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
+                                          : cast<InputSection>(InX::Got);
+  ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>(
+      "_GLOBAL_OFFSET_TABLE_", GotSection, Target->GotBaseSymOff);
+
+  // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
+  // static linking the linker is required to optimize away any references to
+  // __tls_get_addr, so it's not defined anywhere. Create a hidden definition
+  // to avoid the undefined symbol error.
+  if (!InX::DynSymTab)
+    Symtab<ELFT>::X->addIgnored("__tls_get_addr");
+
+  // __ehdr_start is the location of ELF file headers. Note that we define
+  // this symbol unconditionally even when using a linker script, which
+  // differs from the behavior implemented by GNU linker which only define
+  // this symbol if ELF headers are in the memory mapped segment.
+  // __executable_start is not documented, but the expectation of at
+  // least the android libc is that it points to the elf header too.
+  // __dso_handle symbol is passed to cxa_finalize as a marker to identify
+  // each DSO. The address of the symbol doesn't matter as long as they are
+  // different in different DSOs, so we chose the start address of the DSO.
+  for (const char *Name :
+       {"__ehdr_start", "__executable_start", "__dso_handle"})
+    addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN);
+
+  // If linker script do layout we do not need to create any standart symbols.
+  if (Script->Opt.HasSections)
+    return;
+
+  auto Add = [](StringRef S) {
+    return addOptionalRegular<ELFT>(S, Out::ElfHeader, 0, STV_DEFAULT);
+  };
+
+  ElfSym::Bss = Add("__bss_start");
+  ElfSym::End1 = Add("end");
+  ElfSym::End2 = Add("_end");
+  ElfSym::Etext1 = Add("etext");
+  ElfSym::Etext2 = Add("_etext");
+  ElfSym::Edata1 = Add("edata");
+  ElfSym::Edata2 = Add("_edata");
+}
+
+// Sort input sections by section name suffixes for
+// __attribute__((init_priority(N))).
+static void sortInitFini(OutputSectionCommand *Cmd) {
+  if (Cmd)
+    Cmd->sortInitFini();
+}
+
+// Sort input sections by the special rule for .ctors and .dtors.
+static void sortCtorsDtors(OutputSectionCommand *Cmd) {
+  if (Cmd)
+    Cmd->sortCtorsDtors();
+}
+
+// Sort input sections using the list provided by --symbol-ordering-file.
+template <class ELFT> static void sortBySymbolsOrder() {
+  if (Config->SymbolOrderingFile.empty())
+    return;
+
+  // Build a map from symbols to their priorities. Symbols that didn't
+  // appear in the symbol ordering file have the lowest priority 0.
+  // All explicitly mentioned symbols have negative (higher) priorities.
+  DenseMap<StringRef, int> SymbolOrder;
+  int Priority = -Config->SymbolOrderingFile.size();
+  for (StringRef S : Config->SymbolOrderingFile)
+    SymbolOrder.insert({S, Priority++});
+
+  // Build a map from sections to their priorities.
+  DenseMap<SectionBase *, int> SectionOrder;
+  for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) {
+    for (SymbolBody *Body : File->getSymbols()) {
+      auto *D = dyn_cast<DefinedRegular>(Body);
+      if (!D || !D->Section)
+        continue;
+      int &Priority = SectionOrder[D->Section];
+      Priority = std::min(Priority, SymbolOrder.lookup(D->getName()));
+    }
+  }
+
+  // Sort sections by priority.
+  for (BaseCommand *Base : Script->Opt.Commands)
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+      Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
+}
+
+template <class ELFT>
+void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
+  for (InputSectionBase *IS : InputSections) {
+    if (!IS->Live)
+      continue;
+    // Scan all relocations. Each relocation goes through a series
+    // of tests to determine if it needs special treatment, such as
+    // creating GOT, PLT, copy relocations, etc.
+    // Note that relocations for non-alloc sections are directly
+    // processed by InputSection::relocateNonAlloc.
+    if (!(IS->Flags & SHF_ALLOC))
+      continue;
+    if (isa<InputSection>(IS) || isa<EhInputSection>(IS))
+      Fn(*IS);
+  }
+
+  if (!Config->Relocatable) {
+    for (EhInputSection *ES : In<ELFT>::EhFrame->Sections)
+      Fn(*ES);
+  }
+}
+
+template <class ELFT> void Writer<ELFT>::createSections() {
+  for (InputSectionBase *IS : InputSections)
+    if (IS)
+      Factory.addInputSec(IS, getOutputSectionName(IS->Name));
+
+  Script->fabricateDefaultCommands();
+  sortBySymbolsOrder<ELFT>();
+  sortInitFini(findSectionCommand(".init_array"));
+  sortInitFini(findSectionCommand(".fini_array"));
+  sortCtorsDtors(findSectionCommand(".ctors"));
+  sortCtorsDtors(findSectionCommand(".dtors"));
+}
+
+// We want to find how similar two ranks are.
+// The more branches in getSectionRank that match, the more similar they are.
+// Since each branch corresponds to a bit flag, we can just use
+// countLeadingZeros.
+static int getRankProximity(OutputSection *A, OutputSection *B) {
+  return countLeadingZeros(A->SortRank ^ B->SortRank);
+}
+
+static int getRankProximity(OutputSection *A, BaseCommand *B) {
+  if (auto *Cmd = dyn_cast<OutputSectionCommand>(B))
+    if (Cmd->Sec)
+      return getRankProximity(A, Cmd->Sec);
+  return -1;
+}
+
+// When placing orphan sections, we want to place them after symbol assignments
+// so that an orphan after
+//   begin_foo = .;
+//   foo : { *(foo) }
+//   end_foo = .;
+// doesn't break the intended meaning of the begin/end symbols.
+// We don't want to go over sections since findOrphanPos is the
+// one in charge of deciding the order of the sections.
+// We don't want to go over changes to '.', since doing so in
+//  rx_sec : { *(rx_sec) }
+//  . = ALIGN(0x1000);
+//  /* The RW PT_LOAD starts here*/
+//  rw_sec : { *(rw_sec) }
+// would mean that the RW PT_LOAD would become unaligned.
+static bool shouldSkip(BaseCommand *Cmd) {
+  if (isa<OutputSectionCommand>(Cmd))
+    return false;
+  if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
+    return Assign->Name != ".";
+  return true;
+}
+
+// We want to place orphan sections so that they share as much
+// characteristics with their neighbors as possible. For example, if
+// both are rw, or both are tls.
+template <typename ELFT>
+static std::vector<BaseCommand *>::iterator
+findOrphanPos(std::vector<BaseCommand *>::iterator B,
+              std::vector<BaseCommand *>::iterator E) {
+  OutputSection *Sec = cast<OutputSectionCommand>(*E)->Sec;
+
+  // Find the first element that has as close a rank as possible.
+  auto I = std::max_element(B, E, [=](BaseCommand *A, BaseCommand *B) {
+    return getRankProximity(Sec, A) < getRankProximity(Sec, B);
+  });
+  if (I == E)
+    return E;
+
+  // Consider all existing sections with the same proximity.
+  int Proximity = getRankProximity(Sec, *I);
+  for (; I != E; ++I) {
+    auto *Cmd = dyn_cast<OutputSectionCommand>(*I);
+    if (!Cmd || !Cmd->Sec)
+      continue;
+    if (getRankProximity(Sec, Cmd->Sec) != Proximity ||
+        Sec->SortRank < Cmd->Sec->SortRank)
+      break;
+  }
+  auto J = std::find_if(
+      llvm::make_reverse_iterator(I), llvm::make_reverse_iterator(B),
+      [](BaseCommand *Cmd) { return isa<OutputSectionCommand>(Cmd); });
+  I = J.base();
+  while (I != E && shouldSkip(*I))
+    ++I;
+  return I;
+}
+
+template <class ELFT> void Writer<ELFT>::sortSections() {
+  if (Script->Opt.HasSections)
+    Script->adjustSectionsBeforeSorting();
+
+  // Don't sort if using -r. It is not necessary and we want to preserve the
+  // relative order for SHF_LINK_ORDER sections.
+  if (Config->Relocatable)
+    return;
+
+  for (BaseCommand *Base : Script->Opt.Commands)
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+      if (OutputSection *Sec = Cmd->Sec)
+        Sec->SortRank = getSectionRank(Sec);
+
+  if (!Script->Opt.HasSections) {
+    // We know that all the OutputSectionCommands are contiguous in
+    // this case.
+    auto E = Script->Opt.Commands.end();
+    auto I = Script->Opt.Commands.begin();
+    auto IsSection = [](BaseCommand *Base) {
+      return isa<OutputSectionCommand>(Base);
+    };
+    I = std::find_if(I, E, IsSection);
+    E = std::find_if(llvm::make_reverse_iterator(E),
+                     llvm::make_reverse_iterator(I), IsSection)
+            .base();
+    std::stable_sort(I, E, compareSections);
+    return;
+  }
+
+  // Orphan sections are sections present in the input files which are
+  // not explicitly placed into the output file by the linker script.
+  //
+  // The sections in the linker script are already in the correct
+  // order. We have to figuere out where to insert the orphan
+  // sections.
+  //
+  // The order of the sections in the script is arbitrary and may not agree with
+  // compareSections. This means that we cannot easily define a strict weak
+  // ordering. To see why, consider a comparison of a section in the script and
+  // one not in the script. We have a two simple options:
+  // * Make them equivalent (a is not less than b, and b is not less than a).
+  //   The problem is then that equivalence has to be transitive and we can
+  //   have sections a, b and c with only b in a script and a less than c
+  //   which breaks this property.
+  // * Use compareSectionsNonScript. Given that the script order doesn't have
+  //   to match, we can end up with sections a, b, c, d where b and c are in the
+  //   script and c is compareSectionsNonScript less than b. In which case d
+  //   can be equivalent to c, a to b and d < a. As a concrete example:
+  //   .a (rx) # not in script
+  //   .b (rx) # in script
+  //   .c (ro) # in script
+  //   .d (ro) # not in script
+  //
+  // The way we define an order then is:
+  // *  Sort only the orphan sections. They are in the end right now.
+  // *  Move each orphan section to its preferred position. We try
+  //    to put each section in the last position where it it can share
+  //    a PT_LOAD.
+  //
+  // There is some ambiguity as to where exactly a new entry should be
+  // inserted, because Opt.Commands contains not only output section
+  // commands but also other types of commands such as symbol assignment
+  // expressions. There's no correct answer here due to the lack of the
+  // formal specification of the linker script. We use heuristics to
+  // determine whether a new output command should be added before or
+  // after another commands. For the details, look at shouldSkip
+  // function.
+
+  auto I = Script->Opt.Commands.begin();
+  auto E = Script->Opt.Commands.end();
+  auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+      return Cmd->Sec && Cmd->Sec->SectionIndex == INT_MAX;
+    return false;
+  });
+
+  // Sort the orphan sections.
+  std::stable_sort(NonScriptI, E, compareSections);
+
+  // As a horrible special case, skip the first . assignment if it is before any
+  // section. We do this because it is common to set a load address by starting
+  // the script with ". = 0xabcd" and the expectation is that every section is
+  // after that.
+  auto FirstSectionOrDotAssignment =
+      std::find_if(I, E, [](BaseCommand *Cmd) { return !shouldSkip(Cmd); });
+  if (FirstSectionOrDotAssignment != E &&
+      isa<SymbolAssignment>(**FirstSectionOrDotAssignment))
+    ++FirstSectionOrDotAssignment;
+  I = FirstSectionOrDotAssignment;
+
+  while (NonScriptI != E) {
+    auto Pos = findOrphanPos<ELFT>(I, NonScriptI);
+    OutputSection *Orphan = cast<OutputSectionCommand>(*NonScriptI)->Sec;
+
+    // As an optimization, find all sections with the same sort rank
+    // and insert them with one rotate.
+    unsigned Rank = Orphan->SortRank;
+    auto End = std::find_if(NonScriptI + 1, E, [=](BaseCommand *Cmd) {
+      return cast<OutputSectionCommand>(Cmd)->Sec->SortRank != Rank;
+    });
+    std::rotate(Pos, NonScriptI, End);
+    NonScriptI = End;
+  }
+
+  Script->adjustSectionsAfterSorting();
+}
+
+static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
+                           std::function<void(SyntheticSection *)> Fn) {
+  for (SyntheticSection *SS : Sections)
+    if (SS && SS->getParent() && !SS->empty())
+      Fn(SS);
+}
+
+// We need to add input synthetic sections early in createSyntheticSections()
+// to make them visible from linkescript side. But not all sections are always
+// required to be in output. For example we don't need dynamic section content
+// sometimes. This function filters out such unused sections from the output.
+static void removeUnusedSyntheticSections() {
+  // All input synthetic sections that can be empty are placed after
+  // all regular ones. We iterate over them all and exit at first
+  // non-synthetic.
+  for (InputSectionBase *S : llvm::reverse(InputSections)) {
+    SyntheticSection *SS = dyn_cast<SyntheticSection>(S);
+    if (!SS)
+      return;
+    OutputSection *OS = SS->getParent();
+    if (!SS->empty() || !OS)
+      continue;
+    if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable)
+      continue;
+
+    OutputSectionCommand *Cmd = Script->getCmd(OS);
+    std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end();
+    for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) {
+      BaseCommand *B = *I;
+      if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
+        auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS);
+        if (P != ISD->Sections.end())
+          ISD->Sections.erase(P);
+        if (ISD->Sections.empty())
+          Empty = I;
+      }
+    }
+    if (Empty != Cmd->Commands.end())
+      Cmd->Commands.erase(Empty);
+
+    // If there are no other sections in the output section, remove it from the
+    // output.
+    if (Cmd->Commands.empty()) {
+      // Also remove script commands matching the output section.
+      auto &Cmds = Script->Opt.Commands;
+      auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) {
+        if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd))
+          return OSCmd->Sec == OS;
+        return false;
+      });
+      Cmds.erase(I, Cmds.end());
+    }
+  }
+}
+
+// Create output section objects and add them to OutputSections.
+template <class ELFT> void Writer<ELFT>::finalizeSections() {
+  Out::DebugInfo = findSectionInScript(".debug_info");
+  Out::PreinitArray = findSectionInScript(".preinit_array");
+  Out::InitArray = findSectionInScript(".init_array");
+  Out::FiniArray = findSectionInScript(".fini_array");
+
+  // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
+  // symbols for sections, so that the runtime can get the start and end
+  // addresses of each section by section name. Add such symbols.
+  if (!Config->Relocatable) {
+    addStartEndSymbols();
+    for (BaseCommand *Base : Script->Opt.Commands)
+      if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+        if (Cmd->Sec)
+          addStartStopSymbols(Cmd->Sec);
+  }
+
+  // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
+  // It should be okay as no one seems to care about the type.
+  // Even the author of gold doesn't remember why gold behaves that way.
+  // https://sourceware.org/ml/binutils/2002-03/msg00360.html
+  if (InX::DynSymTab)
+    addRegular<ELFT>("_DYNAMIC", InX::Dynamic, 0);
+
+  // Define __rel[a]_iplt_{start,end} symbols if needed.
+  addRelIpltSymbols();
+
+  // This responsible for splitting up .eh_frame section into
+  // pieces. The relocation scan uses those pieces, so this has to be
+  // earlier.
+  applySynthetic({In<ELFT>::EhFrame},
+                 [](SyntheticSection *SS) { SS->finalizeContents(); });
+
+  // Scan relocations. This must be done after every symbol is declared so that
+  // we can correctly decide if a dynamic relocation is needed.
+  forEachRelSec(scanRelocations<ELFT>);
+
+  if (InX::Plt && !InX::Plt->empty())
+    InX::Plt->addSymbols();
+  if (InX::Iplt && !InX::Iplt->empty())
+    InX::Iplt->addSymbols();
+
+  // Now that we have defined all possible global symbols including linker-
+  // synthesized ones. Visit all symbols to give the finishing touches.
+  for (Symbol *S : Symtab<ELFT>::X->getSymbols()) {
+    SymbolBody *Body = S->body();
+
+    if (!includeInSymtab(*Body))
+      continue;
+    if (InX::SymTab)
+      InX::SymTab->addSymbol(Body);
+
+    if (InX::DynSymTab && S->includeInDynsym()) {
+      InX::DynSymTab->addSymbol(Body);
+      if (auto *SS = dyn_cast<SharedSymbol>(Body))
+        if (cast<SharedFile<ELFT>>(SS->File)->isNeeded())
+          In<ELFT>::VerNeed->addSymbol(SS);
+    }
+  }
+
+  // Do not proceed if there was an undefined symbol.
+  if (ErrorCount)
+    return;
+
+  addPredefinedSections();
+  removeUnusedSyntheticSections();
+
+  sortSections();
+
+  // Now that we have the final list, create a list of all the
+  // OutputSectionCommands for convenience.
+  for (BaseCommand *Base : Script->Opt.Commands)
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+      OutputSectionCommands.push_back(Cmd);
+
+  // Prefer command line supplied address over other constraints.
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    auto I = Config->SectionStartMap.find(Cmd->Name);
+    if (I != Config->SectionStartMap.end())
+      Cmd->AddrExpr = [=] { return I->second; };
+  }
+
+  // This is a bit of a hack. A value of 0 means undef, so we set it
+  // to 1 t make __ehdr_start defined. The section number is not
+  // particularly relevant.
+  Out::ElfHeader->SectionIndex = 1;
+
+  unsigned I = 1;
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    Sec->SectionIndex = I++;
+    Sec->ShName = InX::ShStrTab->addString(Sec->Name);
+  }
+
+  // Binary and relocatable output does not have PHDRS.
+  // The headers have to be created before finalize as that can influence the
+  // image base and the dynamic section on mips includes the image base.
+  if (!Config->Relocatable && !Config->OFormatBinary) {
+    Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs();
+    addPtArmExid(Phdrs);
+    Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
+  }
+
+  // Dynamic section must be the last one in this list and dynamic
+  // symbol table section (DynSymTab) must be the first one.
+  applySynthetic({InX::DynSymTab,    InX::Bss,           InX::BssRelRo,
+                  InX::GnuHashTab,   In<ELFT>::HashTab,  InX::SymTab,
+                  InX::ShStrTab,     InX::StrTab,        In<ELFT>::VerDef,
+                  InX::DynStrTab,    InX::GdbIndex,      InX::Got,
+                  InX::MipsGot,      InX::IgotPlt,       InX::GotPlt,
+                  In<ELFT>::RelaDyn, In<ELFT>::RelaIplt, In<ELFT>::RelaPlt,
+                  InX::Plt,          InX::Iplt,          In<ELFT>::EhFrameHdr,
+                  In<ELFT>::VerSym,  In<ELFT>::VerNeed,  InX::Dynamic},
+                 [](SyntheticSection *SS) { SS->finalizeContents(); });
+
+  // Some architectures use small displacements for jump instructions.
+  // It is linker's responsibility to create thunks containing long
+  // jump instructions if jump targets are too far. Create thunks.
+  if (Target->NeedsThunks) {
+    // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented,
+    // these
+    // do not require address information. To support range extension Thunks
+    // we need to assign addresses so that we can tell if jump instructions
+    // are out of range. This will need to turn into a loop that converges
+    // when no more Thunks are added
+    ThunkCreator TC;
+    Script->assignAddresses();
+    if (TC.createThunks(OutputSectionCommands)) {
+      applySynthetic({InX::MipsGot},
+                     [](SyntheticSection *SS) { SS->updateAllocSize(); });
+      if (TC.createThunks(OutputSectionCommands))
+        fatal("All non-range thunks should be created in first call");
+    }
+  }
+
+  // Fill other section headers. The dynamic table is finalized
+  // at the end because some tags like RELSZ depend on result
+  // of finalizing other sections.
+  for (OutputSectionCommand *Cmd : OutputSectionCommands)
+    Cmd->finalize<ELFT>();
+
+  // createThunks may have added local symbols to the static symbol table
+  applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
+                 [](SyntheticSection *SS) { SS->postThunkContents(); });
+}
+
+template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
+  // ARM ABI requires .ARM.exidx to be terminated by some piece of data.
+  // We have the terminater synthetic section class. Add that at the end.
+  OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx");
+  if (!Cmd || !Cmd->Sec || Config->Relocatable)
+    return;
+
+  auto *Sentinel = make<ARMExidxSentinelSection>();
+  Cmd->Sec->addSection(Sentinel);
+  // Add the sentinel to the last of these too.
+  auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
+                          [](const BaseCommand *Base) {
+                            return isa<InputSectionDescription>(Base);
+                          });
+  cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel);
+}
+
+// The linker is expected to define SECNAME_start and SECNAME_end
+// symbols for a few sections. This function defines them.
+template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
+  auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) {
+    // These symbols resolve to the image base if the section does not exist.
+    // A special value -1 indicates end of the section.
+    if (OS) {
+      addOptionalRegular<ELFT>(Start, OS, 0);
+      addOptionalRegular<ELFT>(End, OS, -1);
+    } else {
+      if (Config->Pic)
+        OS = Out::ElfHeader;
+      addOptionalRegular<ELFT>(Start, OS, 0);
+      addOptionalRegular<ELFT>(End, OS, 0);
+    }
+  };
+
+  Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray);
+  Define("__init_array_start", "__init_array_end", Out::InitArray);
+  Define("__fini_array_start", "__fini_array_end", Out::FiniArray);
+
+  if (OutputSection *Sec = findSectionInScript(".ARM.exidx"))
+    Define("__exidx_start", "__exidx_end", Sec);
+}
+
+// If a section name is valid as a C identifier (which is rare because of
+// the leading '.'), linkers are expected to define __start_<secname> and
+// __stop_<secname> symbols. They are at beginning and end of the section,
+// respectively. This is not requested by the ELF standard, but GNU ld and
+// gold provide the feature, and used by many programs.
+template <class ELFT>
+void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
+  StringRef S = Sec->Name;
+  if (!isValidCIdentifier(S))
+    return;
+  addOptionalRegular<ELFT>(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT);
+  addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
+}
+
+template <class ELFT>
+OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) {
+  for (BaseCommand *Base : Script->Opt.Commands)
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+      if (Cmd->Name == Name)
+        return Cmd;
+  return nullptr;
+}
+
+template <class ELFT>
+OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) {
+  if (OutputSectionCommand *Cmd = findSectionCommand(Name))
+    return Cmd->Sec;
+  return nullptr;
+}
+
+static bool needsPtLoad(OutputSection *Sec) {
+  if (!(Sec->Flags & SHF_ALLOC))
+    return false;
+
+  // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
+  // responsible for allocating space for them, not the PT_LOAD that
+  // contains the TLS initialization image.
+  if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS)
+    return false;
+  return true;
+}
+
+// Linker scripts are responsible for aligning addresses. Unfortunately, most
+// linker scripts are designed for creating two PT_LOADs only, one RX and one
+// RW. This means that there is no alignment in the RO to RX transition and we
+// cannot create a PT_LOAD there.
+static uint64_t computeFlags(uint64_t Flags) {
+  if (Config->Omagic)
+    return PF_R | PF_W | PF_X;
+  if (Config->SingleRoRx && !(Flags & PF_W))
+    return Flags | PF_X;
+  return Flags;
+}
+
+// Decide which program headers to create and which sections to include in each
+// one.
+template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
+  std::vector<PhdrEntry> Ret;
+  auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * {
+    Ret.emplace_back(Type, Flags);
+    return &Ret.back();
+  };
+
+  // The first phdr entry is PT_PHDR which describes the program header itself.
+  AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders);
+
+  // PT_INTERP must be the second entry if exists.
+  if (OutputSection *Sec = findSectionInScript(".interp"))
+    AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec);
+
+  // Add the first PT_LOAD segment for regular output sections.
+  uint64_t Flags = computeFlags(PF_R);
+  PhdrEntry *Load = AddHdr(PT_LOAD, Flags);
+
+  // Add the headers. We will remove them if they don't fit.
+  Load->add(Out::ElfHeader);
+  Load->add(Out::ProgramHeaders);
+
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (!(Sec->Flags & SHF_ALLOC))
+      break;
+    if (!needsPtLoad(Sec))
+      continue;
+
+    // Segments are contiguous memory regions that has the same attributes
+    // (e.g. executable or writable). There is one phdr for each segment.
+    // Therefore, we need to create a new phdr when the next section has
+    // different flags or is loaded at a discontiguous address using AT linker
+    // script command.
+    uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
+    if (Cmd->LMAExpr || Flags != NewFlags) {
+      Load = AddHdr(PT_LOAD, NewFlags);
+      Flags = NewFlags;
+    }
+
+    Load->add(Sec);
+  }
+
+  // Add a TLS segment if any.
+  PhdrEntry TlsHdr(PT_TLS, PF_R);
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec->Flags & SHF_TLS)
+      TlsHdr.add(Sec);
+  }
+  if (TlsHdr.First)
+    Ret.push_back(std::move(TlsHdr));
+
+  // Add an entry for .dynamic.
+  if (InX::DynSymTab)
+    AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags())
+        ->add(InX::Dynamic->getParent());
+
+  // PT_GNU_RELRO includes all sections that should be marked as
+  // read-only by dynamic linker after proccessing relocations.
+  PhdrEntry RelRo(PT_GNU_RELRO, PF_R);
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (needsPtLoad(Sec) && isRelroSection(Sec))
+      RelRo.add(Sec);
+  }
+  if (RelRo.First)
+    Ret.push_back(std::move(RelRo));
+
+  // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
+  if (!In<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr &&
+      In<ELFT>::EhFrame->getParent() && In<ELFT>::EhFrameHdr->getParent())
+    AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->getParent()->getPhdrFlags())
+        ->add(In<ELFT>::EhFrameHdr->getParent());
+
+  // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
+  // the dynamic linker fill the segment with random data.
+  if (OutputSection *Sec = findSectionInScript(".openbsd.randomdata"))
+    AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags())->add(Sec);
+
+  // PT_GNU_STACK is a special section to tell the loader to make the
+  // pages for the stack non-executable. If you really want an executable
+  // stack, you can pass -z execstack, but that's not recommended for
+  // security reasons.
+  unsigned Perm;
+  if (Config->ZExecstack)
+    Perm = PF_R | PF_W | PF_X;
+  else
+    Perm = PF_R | PF_W;
+  AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize;
+
+  // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
+  // is expected to perform W^X violations, such as calling mprotect(2) or
+  // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on
+  // OpenBSD.
+  if (Config->ZWxneeded)
+    AddHdr(PT_OPENBSD_WXNEEDED, PF_X);
+
+  // Create one PT_NOTE per a group of contiguous .note sections.
+  PhdrEntry *Note = nullptr;
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec->Type == SHT_NOTE) {
+      if (!Note || Cmd->LMAExpr)
+        Note = AddHdr(PT_NOTE, PF_R);
+      Note->add(Sec);
+    } else {
+      Note = nullptr;
+    }
+  }
+  return Ret;
+}
+
+template <class ELFT>
+void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) {
+  if (Config->EMachine != EM_ARM)
+    return;
+  auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) {
+    return Cmd->Sec->Type == SHT_ARM_EXIDX;
+  });
+  if (I == OutputSectionCommands.end())
+    return;
+
+  // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
+  PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R);
+  ARMExidx.add((*I)->Sec);
+  Phdrs.push_back(ARMExidx);
+}
+
+// The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the
+// first section after PT_GNU_RELRO have to be page aligned so that the dynamic
+// linker can set the permissions.
+template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
+  auto PageAlign = [](OutputSection *Sec) {
+    OutputSectionCommand *Cmd = Script->getCmd(Sec);
+    if (Cmd && !Cmd->AddrExpr)
+      Cmd->AddrExpr = [=] {
+        return alignTo(Script->getDot(), Config->MaxPageSize);
+      };
+  };
+
+  for (const PhdrEntry &P : Phdrs)
+    if (P.p_type == PT_LOAD && P.First)
+      PageAlign(P.First);
+
+  for (const PhdrEntry &P : Phdrs) {
+    if (P.p_type != PT_GNU_RELRO)
+      continue;
+    if (P.First)
+      PageAlign(P.First);
+    // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
+    // have to align it to a page.
+    auto End = OutputSectionCommands.end();
+    auto I =
+        std::find(OutputSectionCommands.begin(), End, Script->getCmd(P.Last));
+    if (I == End || (I + 1) == End)
+      continue;
+    OutputSection *Sec = (*(I + 1))->Sec;
+    if (needsPtLoad(Sec))
+      PageAlign(Sec);
+  }
+}
+
+// Adjusts the file alignment for a given output section and returns
+// its new file offset. The file offset must be the same with its
+// virtual address (modulo the page size) so that the loader can load
+// executables without any address adjustment.
+static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) {
+  OutputSection *First = Sec->FirstInPtLoad;
+  // If the section is not in a PT_LOAD, we just have to align it.
+  if (!First)
+    return alignTo(Off, Sec->Alignment);
+
+  // The first section in a PT_LOAD has to have congruent offset and address
+  // module the page size.
+  if (Sec == First)
+    return alignTo(Off, Config->MaxPageSize, Sec->Addr);
+
+  // If two sections share the same PT_LOAD the file offset is calculated
+  // using this formula: Off2 = Off1 + (VA2 - VA1).
+  return First->Offset + Sec->Addr - First->Addr;
+}
+
+static uint64_t setOffset(OutputSection *Sec, uint64_t Off) {
+  if (Sec->Type == SHT_NOBITS) {
+    Sec->Offset = Off;
+    return Off;
+  }
+
+  Off = getFileAlignment(Off, Sec);
+  Sec->Offset = Off;
+  return Off + Sec->Size;
+}
+
+template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
+  uint64_t Off = 0;
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec->Flags & SHF_ALLOC)
+      Off = setOffset(Sec, Off);
+  }
+  FileSize = alignTo(Off, Config->Wordsize);
+}
+
+// Assign file offsets to output sections.
+template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
+  uint64_t Off = 0;
+  Off = setOffset(Out::ElfHeader, Off);
+  Off = setOffset(Out::ProgramHeaders, Off);
+
+  for (OutputSectionCommand *Cmd : OutputSectionCommands)
+    Off = setOffset(Cmd->Sec, Off);
+
+  SectionHeaderOff = alignTo(Off, Config->Wordsize);
+  FileSize =
+      SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr);
+}
+
+// Finalize the program headers. We call this function after we assign
+// file offsets and VAs to all sections.
+template <class ELFT> void Writer<ELFT>::setPhdrs() {
+  for (PhdrEntry &P : Phdrs) {
+    OutputSection *First = P.First;
+    OutputSection *Last = P.Last;
+    if (First) {
+      P.p_filesz = Last->Offset - First->Offset;
+      if (Last->Type != SHT_NOBITS)
+        P.p_filesz += Last->Size;
+      P.p_memsz = Last->Addr + Last->Size - First->Addr;
+      P.p_offset = First->Offset;
+      P.p_vaddr = First->Addr;
+      if (!P.HasLMA)
+        P.p_paddr = First->getLMA();
+    }
+    if (P.p_type == PT_LOAD)
+      P.p_align = Config->MaxPageSize;
+    else if (P.p_type == PT_GNU_RELRO) {
+      P.p_align = 1;
+      // The glibc dynamic loader rounds the size down, so we need to round up
+      // to protect the last page. This is a no-op on FreeBSD which always
+      // rounds up.
+      P.p_memsz = alignTo(P.p_memsz, Target->PageSize);
+    }
+
+    // The TLS pointer goes after PT_TLS. At least glibc will align it,
+    // so round up the size to make sure the offsets are correct.
+    if (P.p_type == PT_TLS) {
+      Out::TlsPhdr = &P;
+      if (P.p_memsz)
+        P.p_memsz = alignTo(P.p_memsz, P.p_align);
+    }
+  }
+}
+
+// The entry point address is chosen in the following ways.
+//
+// 1. the '-e' entry command-line option;
+// 2. the ENTRY(symbol) command in a linker control script;
+// 3. the value of the symbol start, if present;
+// 4. the address of the first byte of the .text section, if present;
+// 5. the address 0.
+template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
+  // Case 1, 2 or 3. As a special case, if the symbol is actually
+  // a number, we'll use that number as an address.
+  if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry))
+    return B->getVA();
+  uint64_t Addr;
+  if (to_integer(Config->Entry, Addr))
+    return Addr;
+
+  // Case 4
+  if (OutputSection *Sec = findSectionInScript(".text")) {
+    if (Config->WarnMissingEntry)
+      warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
+           utohexstr(Sec->Addr));
+    return Sec->Addr;
+  }
+
+  // Case 5
+  if (Config->WarnMissingEntry)
+    warn("cannot find entry symbol " + Config->Entry +
+         "; not setting start address");
+  return 0;
+}
+
+static uint16_t getELFType() {
+  if (Config->Pic)
+    return ET_DYN;
+  if (Config->Relocatable)
+    return ET_REL;
+  return ET_EXEC;
+}
+
+// This function is called after we have assigned address and size
+// to each section. This function fixes some predefined
+// symbol values that depend on section address and size.
+template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
+  // _etext is the first location after the last read-only loadable segment.
+  // _edata is the first location after the last read-write loadable segment.
+  // _end is the first location after the uninitialized data region.
+  PhdrEntry *Last = nullptr;
+  PhdrEntry *LastRO = nullptr;
+  PhdrEntry *LastRW = nullptr;
+  for (PhdrEntry &P : Phdrs) {
+    if (P.p_type != PT_LOAD)
+      continue;
+    Last = &P;
+    if (P.p_flags & PF_W)
+      LastRW = &P;
+    else
+      LastRO = &P;
+  }
+
+  auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) {
+    if (S) {
+      S->Section = Sec;
+      S->Value = Value;
+    }
+  };
+
+  if (Last) {
+    Set(ElfSym::End1, Last->First, Last->p_memsz);
+    Set(ElfSym::End2, Last->First, Last->p_memsz);
+  }
+  if (LastRO) {
+    Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz);
+    Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
+  }
+  if (LastRW) {
+    Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz);
+    Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
+  }
+
+  if (ElfSym::Bss)
+    ElfSym::Bss->Section = findSectionInScript(".bss");
+
+  // Setup MIPS _gp_disp/__gnu_local_gp symbols which should
+  // be equal to the _gp symbol's value.
+  if (Config->EMachine == EM_MIPS && !ElfSym::MipsGp->Value) {
+    // Find GP-relative section with the lowest address
+    // and use this address to calculate default _gp value.
+    for (const OutputSectionCommand *Cmd : OutputSectionCommands) {
+      OutputSection *OS = Cmd->Sec;
+      if (OS->Flags & SHF_MIPS_GPREL) {
+        ElfSym::MipsGp->Value = OS->Addr + 0x7ff0;
+        break;
+      }
+    }
+  }
+}
+
+template <class ELFT> void Writer<ELFT>::writeHeader() {
+  uint8_t *Buf = Buffer->getBufferStart();
+  memcpy(Buf, "\177ELF", 4);
+
+  // Write the ELF header.
+  auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
+  EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32;
+  EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
+  EHdr->e_ident[EI_VERSION] = EV_CURRENT;
+  EHdr->e_ident[EI_OSABI] = Config->OSABI;
+  EHdr->e_type = getELFType();
+  EHdr->e_machine = Config->EMachine;
+  EHdr->e_version = EV_CURRENT;
+  EHdr->e_entry = getEntryAddr();
+  EHdr->e_shoff = SectionHeaderOff;
+  EHdr->e_ehsize = sizeof(Elf_Ehdr);
+  EHdr->e_phnum = Phdrs.size();
+  EHdr->e_shentsize = sizeof(Elf_Shdr);
+  EHdr->e_shnum = OutputSectionCommands.size() + 1;
+  EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex;
+
+  if (Config->EMachine == EM_ARM)
+    // We don't currently use any features incompatible with EF_ARM_EABI_VER5,
+    // but we don't have any firm guarantees of conformance. Linux AArch64
+    // kernels (as of 2016) require an EABI version to be set.
+    EHdr->e_flags = EF_ARM_EABI_VER5;
+  else if (Config->EMachine == EM_MIPS)
+    EHdr->e_flags = getMipsEFlags<ELFT>();
+
+  if (!Config->Relocatable) {
+    EHdr->e_phoff = sizeof(Elf_Ehdr);
+    EHdr->e_phentsize = sizeof(Elf_Phdr);
+  }
+
+  // Write the program header table.
+  auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+  for (PhdrEntry &P : Phdrs) {
+    HBuf->p_type = P.p_type;
+    HBuf->p_flags = P.p_flags;
+    HBuf->p_offset = P.p_offset;
+    HBuf->p_vaddr = P.p_vaddr;
+    HBuf->p_paddr = P.p_paddr;
+    HBuf->p_filesz = P.p_filesz;
+    HBuf->p_memsz = P.p_memsz;
+    HBuf->p_align = P.p_align;
+    ++HBuf;
+  }
+
+  // Write the section header table. Note that the first table entry is null.
+  auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+  for (OutputSectionCommand *Cmd : OutputSectionCommands)
+    Cmd->Sec->writeHeaderTo<ELFT>(++SHdrs);
+}
+
+// Open a result file.
+template <class ELFT> void Writer<ELFT>::openFile() {
+  if (!Config->Is64 && FileSize > UINT32_MAX) {
+    error("output file too large: " + Twine(FileSize) + " bytes");
+    return;
+  }
+
+  unlinkAsync(Config->OutputFile);
+  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+      FileOutputBuffer::create(Config->OutputFile, FileSize,
+                               FileOutputBuffer::F_executable);
+
+  if (auto EC = BufferOrErr.getError())
+    error("failed to open " + Config->OutputFile + ": " + EC.message());
+  else
+    Buffer = std::move(*BufferOrErr);
+}
+
+template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
+  uint8_t *Buf = Buffer->getBufferStart();
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec->Flags & SHF_ALLOC)
+      Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+  }
+}
+
+// Write section contents to a mmap'ed file.
+template <class ELFT> void Writer<ELFT>::writeSections() {
+  uint8_t *Buf = Buffer->getBufferStart();
+
+  // PPC64 needs to process relocations in the .opd section
+  // before processing relocations in code-containing sections.
+  if (auto *OpdCmd = findSectionCommand(".opd")) {
+    Out::Opd = OpdCmd->Sec;
+    Out::OpdBuf = Buf + Out::Opd->Offset;
+    OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
+  }
+
+  OutputSection *EhFrameHdr =
+      (In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty())
+          ? In<ELFT>::EhFrameHdr->getParent()
+          : nullptr;
+
+  // In -r or -emit-relocs mode, write the relocation sections first as in
+  // ELf_Rel targets we might find out that we need to modify the relocated
+  // section while doing it.
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
+      Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+  }
+
+  for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+    OutputSection *Sec = Cmd->Sec;
+    if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
+        Sec->Type != SHT_RELA)
+      Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+  }
+
+  // The .eh_frame_hdr depends on .eh_frame section contents, therefore
+  // it should be written after .eh_frame is written.
+  if (EhFrameHdr) {
+    OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr);
+    Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+  }
+}
+
+template <class ELFT> void Writer<ELFT>::writeBuildId() {
+  if (!InX::BuildId || !InX::BuildId->getParent())
+    return;
+
+  // Compute a hash of all sections of the output file.
+  uint8_t *Start = Buffer->getBufferStart();
+  uint8_t *End = Start + FileSize;
+  InX::BuildId->writeBuildId({Start, End});
+}
+
+template void elf::writeResult<ELF32LE>();
+template void elf::writeResult<ELF32BE>();
+template void elf::writeResult<ELF64LE>();
+template void elf::writeResult<ELF64BE>();
diff --git a/ELF/Writer.h b/ELF/Writer.h
new file mode 100644 (file)
index 0000000..7fa56be
--- /dev/null
@@ -0,0 +1,61 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_WRITER_H
+#define LLD_ELF_WRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <memory>
+
+namespace lld {
+namespace elf {
+class InputFile;
+class OutputSection;
+class InputSectionBase;
+template <class ELFT> class ObjectFile;
+template <class ELFT> class SymbolTable;
+template <class ELFT> void writeResult();
+template <class ELFT> void markLive();
+bool isRelroSection(const OutputSection *Sec);
+
+// This describes a program header entry.
+// Each contains type, access flags and range of output sections that will be
+// placed in it.
+struct PhdrEntry {
+  PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {}
+  void add(OutputSection *Sec);
+
+  uint64_t p_paddr = 0;
+  uint64_t p_vaddr = 0;
+  uint64_t p_memsz = 0;
+  uint64_t p_filesz = 0;
+  uint64_t p_offset = 0;
+  uint32_t p_align = 0;
+  uint32_t p_type = 0;
+  uint32_t p_flags = 0;
+
+  OutputSection *First = nullptr;
+  OutputSection *Last = nullptr;
+  bool HasLMA = false;
+};
+
+llvm::StringRef getOutputSectionName(llvm::StringRef Name);
+
+template <class ELFT> uint32_t getMipsEFlags();
+
+uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
+                         llvm::StringRef FileName);
+
+bool isMipsN32Abi(const InputFile *F);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ec97986
--- /dev/null
@@ -0,0 +1,62 @@
+==============================================================================
+lld License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2011-2016 by the contributors listed in CREDITS.TXT
+All rights reserved.
+
+Developed by:
+
+    LLVM Team
+
+    University of Illinois at Urbana-Champaign
+
+    http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the LLVM Team, University of Illinois at
+      Urbana-Champaign, nor the names of its contributors may be used to
+      endorse or promote products derived from this Software without specific
+      prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+The lld software contains code written by third parties.  Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the lld Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program             Directory
+-------             ---------
+<none yet>
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..38a6b48
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+
+LLVM Linker (lld)
+==============================
+
+This directory and its subdirectories contain source code for the LLVM Linker, a
+modular cross platform linker which is built as part of the LLVM compiler
+infrastructure project.
+
+lld is open source software. You may freely distribute it under the terms of
+the license agreement found in LICENSE.txt.
+
diff --git a/cmake/modules/AddLLD.cmake b/cmake/modules/AddLLD.cmake
new file mode 100644 (file)
index 0000000..fd1d441
--- /dev/null
@@ -0,0 +1,77 @@
+macro(add_lld_library name)
+  cmake_parse_arguments(ARG
+    "SHARED"
+    ""
+    ""
+    ${ARGN})
+  if(ARG_SHARED)
+    set(ARG_ENABLE_SHARED SHARED)
+  endif()
+  llvm_add_library(${name} ${ARG_ENABLE_SHARED} ${ARG_UNPARSED_ARGUMENTS})
+  set_target_properties(${name} PROPERTIES FOLDER "lld libraries")
+
+  if (LLD_BUILD_TOOLS)
+    if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
+        NOT LLVM_DISTRIBUTION_COMPONENTS)
+      set(export_to_lldtargets EXPORT lldTargets)
+      set_property(GLOBAL PROPERTY LLD_HAS_EXPORTS True)
+    endif()
+
+    install(TARGETS ${name}
+      COMPONENT ${name}
+      ${export_to_lldtargets}
+      LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+      ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+      RUNTIME DESTINATION bin)
+
+    if (${ARG_SHARED} AND NOT CMAKE_CONFIGURATION_TYPES)
+      add_custom_target(install-${name}
+        DEPENDS ${name}
+        COMMAND "${CMAKE_COMMAND}"
+          -DCMAKE_INSTALL_COMPONENT=${name}
+          -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
+    endif()
+    set_property(GLOBAL APPEND PROPERTY LLD_EXPORTS ${name})
+  endif()
+endmacro(add_lld_library)
+
+macro(add_lld_executable name)
+  add_llvm_executable(${name} ${ARGN})
+  set_target_properties(${name} PROPERTIES FOLDER "lld executables")
+endmacro(add_lld_executable)
+
+macro(add_lld_tool name)
+  if (NOT LLD_BUILD_TOOLS)
+    set(EXCLUDE_FROM_ALL ON)
+  endif()
+
+  add_lld_executable(${name} ${ARGN})
+
+  if (LLD_BUILD_TOOLS)
+    if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR
+        NOT LLVM_DISTRIBUTION_COMPONENTS)
+      set(export_to_lldtargets EXPORT lldTargets)
+      set_property(GLOBAL PROPERTY LLD_HAS_EXPORTS True)
+    endif()
+
+    install(TARGETS ${name}
+      ${export_to_lldtargets}
+      RUNTIME DESTINATION bin
+      COMPONENT ${name})
+
+    if(NOT CMAKE_CONFIGURATION_TYPES)
+      add_custom_target(install-${name}
+        DEPENDS ${name}
+        COMMAND "${CMAKE_COMMAND}"
+        -DCMAKE_INSTALL_COMPONENT=${name}
+        -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
+    endif()
+    set_property(GLOBAL APPEND PROPERTY LLD_EXPORTS ${name})
+  endif()
+endmacro()
+
+macro(add_lld_symlink name dest)
+  add_llvm_tool_symlink(${name} ${dest} ALWAYS_GENERATE)
+  # Always generate install targets
+  llvm_install_symlink(${name} ${dest} ALWAYS_GENERATE)
+endmacro()
diff --git a/cmake/modules/FindVTune.cmake b/cmake/modules/FindVTune.cmake
new file mode 100644 (file)
index 0000000..bd0cbe9
--- /dev/null
@@ -0,0 +1,31 @@
+# - Find VTune ittnotify.
+# Defines:
+# VTune_FOUND
+# VTune_INCLUDE_DIRS
+# VTune_LIBRARIES
+
+set(dirs
+  "$ENV{VTUNE_AMPLIFIER_XE_2013_DIR}/"
+  "C:/Program Files (x86)/Intel/VTune Amplifier XE 2013/"
+  "$ENV{VTUNE_AMPLIFIER_XE_2011_DIR}/"
+  "C:/Program Files (x86)/Intel/VTune Amplifier XE 2011/"
+  )
+
+find_path(VTune_INCLUDE_DIRS ittnotify.h
+    PATHS ${dirs}
+    PATH_SUFFIXES include)
+
+if (CMAKE_SIZEOF_VOID_P MATCHES "8")
+  set(vtune_lib_dir lib64)
+else()
+  set(vtune_lib_dir lib32)
+endif()
+
+find_library(VTune_LIBRARIES libittnotify
+    HINTS "${VTune_INCLUDE_DIRS}/.."
+    PATHS ${dirs}
+    PATH_SUFFIXES ${vtune_lib_dir})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+    VTune DEFAULT_MSG VTune_LIBRARIES VTune_INCLUDE_DIRS)
diff --git a/docs/AtomLLD.rst b/docs/AtomLLD.rst
new file mode 100644 (file)
index 0000000..614e568
--- /dev/null
@@ -0,0 +1,62 @@
+ATOM-based lld
+==============
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+ATOM-based lld is a new set of modular code for creating linker tools.
+Currently it supports Mach-O.
+
+* End-User Features:
+
+  * Compatible with existing linker options
+  * Reads standard Object Files
+  * Writes standard Executable Files
+  * Remove clang's reliance on "the system linker"
+  * Uses the LLVM `"UIUC" BSD-Style license`__.
+
+* Applications:
+
+  * Modular design
+  * Support cross linking
+  * Easy to add new CPU support
+  * Can be built as static tool or library
+
+* Design and Implementation:
+
+  * Extensive unit tests
+  * Internal linker model can be dumped/read to textual format
+  * Additional linking features can be plugged in as "passes"
+  * OS specific and CPU specific code factored out
+
+Why a new linker?
+-----------------
+
+The fact that clang relies on whatever linker tool you happen to have installed
+means that clang has been very conservative adopting features which require a
+recent linker.
+
+In the same way that the MC layer of LLVM has removed clang's reliance on the
+system assembler tool, the lld project will remove clang's reliance on the
+system linker tool.
+
+
+Contents
+--------
+
+.. toctree::
+   :maxdepth: 2
+
+   design
+   getting_started
+   development
+   open_projects
+   sphinx_intro
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
+__ http://llvm.org/docs/DeveloperPolicy.html#license
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..112ce35
--- /dev/null
@@ -0,0 +1,8 @@
+if (LLVM_ENABLE_SPHINX)
+  include(AddSphinxTarget)
+  if (SPHINX_FOUND)
+    if (${SPHINX_OUTPUT_HTML})
+      add_sphinx_target(html lld)
+    endif()
+  endif()
+endif()
diff --git a/docs/Driver.rst b/docs/Driver.rst
new file mode 100644 (file)
index 0000000..27b3787
--- /dev/null
@@ -0,0 +1,82 @@
+======
+Driver
+======
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+.. contents::
+   :local:
+
+Introduction
+============
+
+This document describes the lld driver. The purpose of this document is to
+describe both the motivation and design goals for the driver, as well as details
+of the internal implementation.
+
+Overview
+========
+
+The lld driver is designed to support a number of different command line
+interfaces. The main interfaces we plan to support are binutils' ld, Apple's
+ld, and Microsoft's link.exe.
+
+Flavors
+-------
+
+Each of these different interfaces is referred to as a flavor. There is also an
+extra flavor "core" which is used to exercise the core functionality of the
+linker it the test suite.
+
+* gnu
+* darwin
+* link
+* core
+
+Selecting a Flavor
+^^^^^^^^^^^^^^^^^^
+
+There are two different ways to tell lld which flavor to be. They are checked in
+order, so the second overrides the first. The first is to symlink :program:`lld`
+as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify
+it as the first command line argument using ``-flavor``::
+
+  $ lld -flavor gnu
+
+There is a shortcut for ``-flavor core`` as ``-core``.
+
+
+Adding an Option to an existing Flavor
+======================================
+
+#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`.
+
+#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method
+   for the option.
+
+#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file:
+   `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter
+   for corresponding to the option.
+
+#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option.
+
+
+Adding a Flavor
+===============
+
+#. Add an entry for the flavor in :file:`include/lld/Driver/Driver.h` to
+   :cpp:class:`lld::UniversalDriver::Flavor`.
+
+#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to
+   :cpp:func:`lld::Driver::strToFlavor` and
+   :cpp:func:`lld::UniversalDriver::link`.
+   This allows the flavor to be selected via symlink and `-flavor`.
+
+#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that
+   describes the options. If the options are a superset of another driver, that
+   driver's td file can simply be included. The :file:`{flavor}Options.td` file
+   must also be added to :file:`lib/Driver/CMakeLists.txt`.
+
+#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver`
+   in :file:`lib/Driver/{flavor}Driver.cpp`.
diff --git a/docs/NewLLD.rst b/docs/NewLLD.rst
new file mode 100644 (file)
index 0000000..67f6b36
--- /dev/null
@@ -0,0 +1,314 @@
+The ELF and COFF Linkers
+========================
+
+The ELF Linker as a Library
+---------------------------
+
+You can embed LLD to your program by linking against it and calling the linker's
+entry point function lld::elf::link.
+
+The current policy is that it is your reponsibility to give trustworthy object
+files. The function is guaranteed to return as long as you do not pass corrupted
+or malicious object files. A corrupted file could cause a fatal error or SEGV.
+That being said, you don't need to worry too much about it if you create object
+files in the usual way and give them to the linker. It is naturally expected to
+work, or otherwise it's a linker's bug.
+
+Design
+======
+
+We will describe the design of the linkers in the rest of the document.
+
+Key Concepts
+------------
+
+Linkers are fairly large pieces of software.
+There are many design choices you have to make to create a complete linker.
+
+This is a list of design choices we've made for ELF and COFF LLD.
+We believe that these high-level design choices achieved a right balance
+between speed, simplicity and extensibility.
+
+* Implement as native linkers
+
+  We implemented the linkers as native linkers for each file format.
+
+  The two linkers share the same design but do not share code.
+  Sharing code makes sense if the benefit is worth its cost.
+  In our case, ELF and COFF are different enough that we thought the layer to
+  abstract the differences wouldn't worth its complexity and run-time cost.
+  Elimination of the abstract layer has greatly simplified the implementation.
+
+* Speed by design
+
+  One of the most important things in archiving high performance is to
+  do less rather than do it efficiently.
+  Therefore, the high-level design matters more than local optimizations.
+  Since we are trying to create a high-performance linker,
+  it is very important to keep the design as efficient as possible.
+
+  Broadly speaking, we do not do anything until we have to do it.
+  For example, we do not read section contents or relocations
+  until we need them to continue linking.
+  When we need to do some costly operation (such as looking up
+  a hash table for each symbol), we do it only once.
+  We obtain a handler (which is typically just a pointer to actual data)
+  on the first operation and use it throughout the process.
+
+* Efficient archive file handling
+
+  LLD's handling of archive files (the files with ".a" file extension) is different
+  from the traditional Unix linkers and similar to Windows linkers.
+  We'll describe how the traditional Unix linker handles archive files,
+  what the problem is, and how LLD approached the problem.
+
+  The traditional Unix linker maintains a set of undefined symbols during linking.
+  The linker visits each file in the order as they appeared in the command line
+  until the set becomes empty. What the linker would do depends on file type.
+
+  - If the linker visits an object file, the linker links object files to the result,
+    and undefined symbols in the object file are added to the set.
+
+  - If the linker visits an archive file, it checks for the archive file's symbol table
+    and extracts all object files that have definitions for any symbols in the set.
+
+  This algorithm sometimes leads to a counter-intuitive behavior.
+  If you give archive files before object files, nothing will happen
+  because when the linker visits archives, there is no undefined symbols in the set.
+  As a result, no files are extracted from the first archive file,
+  and the link is done at that point because the set is empty after it visits one file.
+
+  You can fix the problem by reordering the files,
+  but that cannot fix the issue of mutually-dependent archive files.
+
+  Linking mutually-dependent archive files is tricky.
+  You may specify the same archive file multiple times to
+  let the linker visit it more than once.
+  Or, you may use the special command line options, `--start-group` and `--end-group`,
+  to let the linker loop over the files between the options until
+  no new symbols are added to the set.
+
+  Visiting the same archive files multiple makes the linker slower.
+
+  Here is how LLD approaches the problem. Instead of memorizing only undefined symbols,
+  we program LLD so that it memorizes all symbols.
+  When it sees an undefined symbol that can be resolved by extracting an object file
+  from an archive file it previously visited, it immediately extracts the file and link it.
+  It is doable because LLD does not forget symbols it have seen in archive files.
+
+  We believe that the LLD's way is efficient and easy to justify.
+
+  The semantics of LLD's archive handling is different from the traditional Unix's.
+  You can observe it if you carefully craft archive files to exploit it.
+  However, in reality, we don't know any program that cannot link
+  with our algorithm so far, so it's not going to cause trouble.
+
+Numbers You Want to Know
+------------------------
+
+To give you intuition about what kinds of data the linker is mainly working on,
+I'll give you the list of objects and their numbers LLD has to read and process
+in order to link a very large executable. In order to link Chrome with debug info,
+which is roughly 2 GB in output size, LLD reads
+
+- 17,000 files,
+- 1,800,000 sections,
+- 6,300,000 symbols, and
+- 13,000,000 relocations.
+
+LLD produces the 2 GB executable in 15 seconds.
+
+These numbers vary depending on your program, but in general,
+you have a lot of relocations and symbols for each file.
+If your program is written in C++, symbol names are likely to be
+pretty long because of name mangling.
+
+It is important to not waste time on relocations and symbols.
+
+In the above case, the total amount of symbol strings is 450 MB,
+and inserting all of them to a hash table takes 1.5 seconds.
+Therefore, if you causally add a hash table lookup for each symbol,
+it would slow down the linker by 10%. So, don't do that.
+
+On the other hand, you don't have to pursue efficiency
+when handling files.
+
+Important Data Structures
+-------------------------
+
+We will describe the key data structures in LLD in this section.
+The linker can be understood as the interactions between them.
+Once you understand their functions, the code of the linker should look obvious to you.
+
+* SymbolBody
+
+  SymbolBody is a class to represent symbols.
+  They are created for symbols in object files or archive files.
+  The linker creates linker-defined symbols as well.
+
+  There are basically three types of SymbolBodies: Defined, Undefined, or Lazy.
+
+  - Defined symbols are for all symbols that are considered as "resolved",
+    including real defined symbols, COMDAT symbols, common symbols,
+    absolute symbols, linker-created symbols, etc.
+  - Undefined symbols represent undefined symbols, which need to be replaced by
+    Defined symbols by the resolver until the link is complete.
+  - Lazy symbols represent symbols we found in archive file headers
+    which can turn into Defined if we read archieve members.
+
+* Symbol
+
+  A Symbol is a container for a SymbolBody. There's only one Symbol for each
+  unique symbol name (this uniqueness is guaranteed by the symbol table).
+  Each global symbol has only one SymbolBody at any one time, which is
+  the SymbolBody stored within a memory region of the Symbol large enough
+  to store any SymbolBody.
+
+  As the resolver reads symbols from input files, it replaces the Symbol's
+  SymbolBody with the "best" SymbolBody for its symbol name by constructing
+  the new SymbolBody in place on top of the existing SymbolBody. For example,
+  if the resolver is given a defined symbol, and the SymbolBody with its name
+  is undefined, it will construct a Defined SymbolBody over the Undefined
+  SymbolBody.
+
+  This means that each SymbolBody pointer always points to the best SymbolBody,
+  and it is possible to get from a SymbolBody to a Symbol, or vice versa,
+  by adding or subtracting a fixed offset. This memory layout helps reduce
+  the cache miss rate through high locality and a small number of required
+  pointer indirections.
+
+* SymbolTable
+
+  SymbolTable is basically a hash table from strings to Symbols
+  with logic to resolve symbol conflicts. It resolves conflicts by symbol type.
+
+  - If we add Defined and Undefined symbols, the symbol table will keep the former.
+  - If we add Defined and Lazy symbols, it will keep the former.
+  - If we add Lazy and Undefined, it will keep the former,
+    but it will also trigger the Lazy symbol to load the archive member
+    to actually resolve the symbol.
+
+* Chunk (COFF specific)
+
+  Chunk represents a chunk of data that will occupy space in an output.
+  Each regular section becomes a chunk.
+  Chunks created for common or BSS symbols are not backed by sections.
+  The linker may create chunks to append additional data to an output as well.
+
+  Chunks know about their size, how to copy their data to mmap'ed outputs,
+  and how to apply relocations to them.
+  Specifically, section-based chunks know how to read relocation tables
+  and how to apply them.
+
+* InputSection (ELF specific)
+
+  Since we have less synthesized data for ELF, we don't abstract slices of
+  input files as Chunks for ELF. Instead, we directly use the input section
+  as an internal data type.
+
+  InputSection knows about their size and how to copy themselves to
+  mmap'ed outputs, just like COFF Chunks.
+
+* OutputSection
+
+  OutputSection is a container of InputSections (ELF) or Chunks (COFF).
+  An InputSection or Chunk belongs to at most one OutputSection.
+
+There are mainly three actors in this linker.
+
+* InputFile
+
+  InputFile is a superclass of file readers.
+  We have a different subclass for each input file type,
+  such as regular object file, archive file, etc.
+  They are responsible for creating and owning SymbolBodies and
+  InputSections/Chunks.
+
+* Writer
+
+  The writer is responsible for writing file headers and InputSections/Chunks to a file.
+  It creates OutputSections, put all InputSections/Chunks into them,
+  assign unique, non-overlapping addresses and file offsets to them,
+  and then write them down to a file.
+
+* Driver
+
+  The linking process is driven by the driver. The driver:
+
+  - processes command line options,
+  - creates a symbol table,
+  - creates an InputFile for each input file and puts all symbols within into the symbol table,
+  - checks if there's no remaining undefined symbols,
+  - creates a writer,
+  - and passes the symbol table to the writer to write the result to a file.
+
+Link-Time Optimization
+----------------------
+
+LTO is implemented by handling LLVM bitcode files as object files.
+The linker resolves symbols in bitcode files normally. If all symbols
+are successfully resolved, it then runs LLVM passes
+with all bitcode files to convert them to one big regular ELF/COFF file.
+Finally, the linker replaces bitcode symbols with ELF/COFF symbols,
+so that they are linked as if they were in the native format from the beginning.
+
+The details are described in this document.
+http://llvm.org/docs/LinkTimeOptimization.html
+
+Glossary
+--------
+
+* RVA (COFF)
+
+  Short for Relative Virtual Address.
+
+  Windows executables or DLLs are not position-independent; they are
+  linked against a fixed address called an image base. RVAs are
+  offsets from an image base.
+
+  Default image bases are 0x140000000 for executables and 0x18000000
+  for DLLs. For example, when we are creating an executable, we assume
+  that the executable will be loaded at address 0x140000000 by the
+  loader, so we apply relocations accordingly. Result texts and data
+  will contain raw absolute addresses.
+
+* VA
+
+  Short for Virtual Address. For COFF, it is equivalent to RVA + image base.
+
+* Base relocations (COFF)
+
+  Relocation information for the loader. If the loader decides to map
+  an executable or a DLL to a different address than their image
+  bases, it fixes up binaries using information contained in the base
+  relocation table. A base relocation table consists of a list of
+  locations containing addresses. The loader adds a difference between
+  RVA and actual load address to all locations listed there.
+
+  Note that this run-time relocation mechanism is much simpler than ELF.
+  There's no PLT or GOT. Images are relocated as a whole just
+  by shifting entire images in memory by some offsets. Although doing
+  this breaks text sharing, I think this mechanism is not actually bad
+  on today's computers.
+
+* ICF
+
+  Short for Identical COMDAT Folding (COFF) or Identical Code Folding (ELF).
+
+  ICF is an optimization to reduce output size by merging read-only sections
+  by not only their names but by their contents. If two read-only sections
+  happen to have the same metadata, actual contents and relocations,
+  they are merged by ICF. It is known as an effective technique,
+  and it usually reduces C++ program's size by a few percent or more.
+
+  Note that this is not entirely sound optimization. C/C++ require
+  different functions have different addresses. If a program depends on
+  that property, it would fail at runtime.
+
+  On Windows, that's not really an issue because MSVC link.exe enabled
+  the optimization by default. As long as your program works
+  with the linker's default settings, your program should be safe with ICF.
+
+  On Unix, your program is generally not guaranteed to be safe with ICF,
+  although large programs happen to work correctly.
+  LLD works fine with ICF for example.
diff --git a/docs/README.txt b/docs/README.txt
new file mode 100644 (file)
index 0000000..eb09a2d
--- /dev/null
@@ -0,0 +1,12 @@
+lld Documentation
+=================
+
+The lld documentation is written using the Sphinx documentation generator. It is
+currently tested with Sphinx 1.1.3.
+
+We currently use the 'nature' theme and a Beaker inspired structure.
+
+To rebuild documents into html:
+
+   [/lld/docs]> make html
+
diff --git a/docs/Readers.rst b/docs/Readers.rst
new file mode 100644 (file)
index 0000000..b69a0b3
--- /dev/null
@@ -0,0 +1,174 @@
+.. _Readers:
+
+Developing lld Readers
+======================
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+Introduction
+------------
+
+The purpose of a "Reader" is to take an object file in a particular format
+and create an `lld::File`:cpp:class: (which is a graph of Atoms)
+representing the object file.  A Reader inherits from
+`lld::Reader`:cpp:class: which lives in
+:file:`include/lld/Core/Reader.h` and
+:file:`lib/Core/Reader.cpp`.
+
+The Reader infrastructure for an object format ``Foo`` requires the
+following pieces in order to fit into lld:
+
+:file:`include/lld/ReaderWriter/ReaderFoo.h`
+
+   .. cpp:class:: ReaderOptionsFoo : public ReaderOptions
+
+      This Options class is the only way to configure how the Reader will
+      parse any file into an `lld::Reader`:cpp:class: object.  This class
+      should be declared in the `lld`:cpp:class: namespace.
+
+   .. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader)
+
+      This factory function configures and create the Reader. This function
+      should be declared in the `lld`:cpp:class: namespace.
+
+:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp`
+
+   .. cpp:class:: ReaderFoo : public Reader
+
+      This is the concrete Reader class which can be called to parse
+      object files. It should be declared in an anonymous namespace or
+      if there is shared code with the `lld::WriterFoo`:cpp:class: you
+      can make a nested namespace (e.g. `lld::foo`:cpp:class:).
+
+You may have noticed that :cpp:class:`ReaderFoo` is not declared in the
+``.h`` file. An important design aspect of lld is that all Readers are
+created *only* through an object-format-specific
+:cpp:func:`createReaderFoo` factory function. The creation of the Reader is
+parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options
+class is the one-and-only way to control how the Reader operates when
+parsing an input file into an Atom graph. For instance, you may want the
+Reader to only accept certain architectures. The options class can be
+instantiated from command line options or be programmatically configured.
+
+Where to start
+--------------
+
+The lld project already has a skeleton of source code for Readers for
+``ELF``, ``PECOFF``, ``MachO``, and lld's native ``YAML`` graph format.
+If your file format is a variant of one of those, you should modify the
+existing Reader to support your variant. This is done by customizing the Options
+class for the Reader and making appropriate changes to the ``.cpp`` file to
+interpret those options and act accordingly.
+
+If your object file format is not a variant of any existing Reader, you'll need
+to create a new Reader subclass with the organization described above.
+
+Readers are factories
+---------------------
+
+The linker will usually only instantiate your Reader once.  That one Reader will
+have its loadFile() method called many times with different input files.
+To support multithreaded linking, the Reader may be parsing multiple input
+files in parallel. Therefore, there should be no parsing state in you Reader
+object.  Any parsing state should be in ivars of your File subclass or in
+some temporary object.
+
+The key method to implement in a reader is::
+
+  virtual error_code loadFile(LinkerInput &input,
+                              std::vector<std::unique_ptr<File>> &result);
+
+It takes a memory buffer (which contains the contents of the object file
+being read) and returns an instantiated lld::File object which is
+a collection of Atoms. The result is a vector of File pointers (instead of
+simple a File pointer) because some file formats allow multiple object
+"files" to be encoded in one file system file.
+
+
+Memory Ownership
+----------------
+
+Atoms are always owned by their File object. During core linking when Atoms
+are coalesced or stripped away, core linking does not delete them.
+Core linking just removes those unused Atoms from its internal list.
+The destructor of a File object is responsible for deleting all Atoms it
+owns, and if ownership of the MemoryBuffer was passed to it, the File
+destructor needs to delete that too.
+
+Making Atoms
+------------
+
+The internal model of lld is purely Atom based.  But most object files do not
+have an explicit concept of Atoms, instead most have "sections". The way
+to think of this is that a section is just a list of Atoms with common
+attributes.
+
+The first step in parsing section-based object files is to cleave each
+section into a list of Atoms. The technique may vary by section type. For
+code sections (e.g. .text), there are usually symbols at the start of each
+function. Those symbol addresses are the points at which the section is
+cleaved into discrete Atoms.  Some file formats (like ELF) also include the
+length of each symbol in the symbol table. Otherwise, the length of each
+Atom is calculated to run to the start of the next symbol or the end of the
+section.
+
+Other sections types can be implicitly cleaved. For instance c-string literals
+or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at
+the content of the section.  It is important to cleave sections into Atoms
+to remove false dependencies. For instance the .eh_frame section often
+has no symbols, but contains "pointers" to the functions for which it
+has unwind info.  If the .eh_frame section was not cleaved (but left as one
+big Atom), there would always be a reference (from the eh_frame Atom) to
+each function.  So the linker would be unable to coalesce or dead stripped
+away the function atoms.
+
+The lld Atom model also requires that a reference to an undefined symbol be
+modeled as a Reference to an UndefinedAtom. So the Reader also needs to
+create an UndefinedAtom for each undefined symbol in the object file.
+
+Once all Atoms have been created, the second step is to create References
+(recall that Atoms are "nodes" and References are "edges"). Most References
+are created by looking at the "relocation records" in the object file. If
+a function contains a call to "malloc", there is usually a relocation record
+specifying the address in the section and the symbol table index. Your
+Reader will need to convert the address to an Atom and offset and the symbol
+table index into a target Atom. If "malloc" is not defined in the object file,
+the target Atom of the Reference will be an UndefinedAtom.
+
+
+Performance
+-----------
+Once you have the above working to parse an object file into Atoms and
+References, you'll want to look at performance.  Some techniques that can
+help performance are:
+
+* Use llvm::BumpPtrAllocator or pre-allocate one big vector<Reference> and then
+  just have each atom point to its subrange of References in that vector.
+  This can be faster that allocating each Reference as separate object.
+* Pre-scan the symbol table and determine how many atoms are in each section
+  then allocate space for all the Atom objects at once.
+* Don't copy symbol names or section content to each Atom, instead use
+  StringRef and ArrayRef in each Atom to point to its name and content in the
+  MemoryBuffer.
+
+
+Testing
+-------
+
+We are still working on infrastructure to test Readers. The issue is that
+you don't want to check in binary files to the test suite. And the tools
+for creating your object file from assembly source may not be available on
+every OS.
+
+We are investigating a way to use YAML to describe the section, symbols,
+and content of a file. Then have some code which will write out an object
+file from that YAML description.
+
+Once that is in place, you can write test cases that contain section/symbols
+YAML and is run through the linker to produce Atom/References based YAML which
+is then run through FileCheck to verify the Atoms and References are as
+expected.
+
+
+
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
new file mode 100644 (file)
index 0000000..fa6536f
--- /dev/null
@@ -0,0 +1,182 @@
+=======================
+lld 5.0.0 Release Notes
+=======================
+
+.. contents::
+    :local:
+
+.. warning::
+   These are in-progress notes for the upcoming LLVM 5.0.0 release.
+   Release notes for previous releases can be found on
+   `the Download Page <http://releases.llvm.org/download.html>`_.
+
+Introduction
+============
+
+lld is a linker from the LLVM project. It supports ELF (Unix), COFF (Windows)
+and Mach-O (macOS), and it is generally faster than the GNU bfd or gold linkers
+or the MSVC linker.
+
+lld is designed to be a drop-in replacement for the system linkers, so that
+users don't need to change their build systems other than swapping the linker
+command.
+
+All lld releases may be downloaded from the `LLVM releases web site
+<http://llvm.org/releases/>`_.
+
+Non-comprehensive list of changes in this release
+=================================================
+
+ELF Improvements
+----------------
+
+* First and foremost, a lot of compatibility issues and bugs have been fixed.
+  Linker script support has significantly improved. As a result, we believe you
+  are very likely to be able to link your programs with lld without experiencing
+  any problem now.
+
+* Error message format has changed in order to improve readability.
+  Traditionally, linker's error messages are concise and arguably too terse.
+  This is an example of lld 4.0's error message (they are actually in one line)::
+
+    /ssd/clang/bin/ld.lld: error: /ssd/llvm-project/lld/ELF/Writer.cpp:207:
+      undefined symbol 'lld::elf::EhFrameSection::addSection()'
+
+  It is not easy to read because too much information is packed into a single line
+  and the embedded text, particularly a symbol name, is sometimes too long.
+  In lld 5.0, we use more vertical space to print out error messages in a more
+  structured manner like this::
+
+    bin/ld.lld: error: undefined symbol: lld::elf::EhFrameSection::addSection()
+    >>> Referenced by Writer.cpp:207 (/ssd/llvm-project/lld/ELF/Writer.cpp:207)
+    >>>               Writer.cpp.o in archive lib/liblldELF.a
+
+  As a bonus, the new error message contains source code location of the error
+  if it is available from debug info.
+
+* ``./configure`` scripts generated by GNU autoconf determines whether a linker
+  supports modern GNU-compatible features or not by searching for "GNU" in the
+  ``--help`` message. To be compatible with the scripts, we decided to add a
+  string "(compatible with GNU linkers)" to our ``--help`` message. This is a
+  hack, but just like the web browser's User-Agent string (which everyone still
+  claim they are "Mozilla/5.0"), we had no choice other than doing this to claim
+  that we accept GNU-compatible options.
+
+* The ``-Map`` option is added. The option is to make the linker to print out how
+  input files are mapped to the output file. Here is an example::
+
+    Address          Size             Align Out     In      Symbol
+    00000000016d84d8 00000000008f8f50     8 .eh_frame
+    00000000016d84d8 00000000008f8f50     8         <internal>:(.eh_frame)
+    0000000001fd2000 00000000034b3bd0    16 .text
+    0000000001fd2000 000000000000002a     1         /usr/lib/x86_64-linux-gnu/crt1.o:(.text)
+    0000000001fd2000 0000000000000000     0                 _start
+    0000000001fd202a 0000000000000000     1         /usr/lib/x86_64-linux-gnu/crti.o:(.text)
+    0000000001fd2030 00000000000000bd    16         /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o:(.text)
+    0000000001fd2030 0000000000000000     0                 deregister_tm_clones
+    0000000001fd2060 0000000000000000     0                 register_tm_clones
+
+  This format is not the same as GNU linkers as our linker internal data
+  structure is different from them but contains the same amount of information
+  and should be more readable than their outputs.
+
+  As with other lld features, the ``-Map`` option is designed with speed in mind.
+  The option would generate a hundred megabyte text file if you link a large
+  program with it. lld can usually do that in a few seconds, and it is generally
+  a few times faster than the GNU gold's ``-Map`` option.
+
+* lld's ``--gdb-index`` option used to be slow, but we sped it up so that it is
+  at least as fast as the GNU gold.
+
+* Some nonstandard relocations, such as R_X86_64_8 or R_X86_64_16, are supported.
+  They are not used for 32/64-bit applications, but some 16-bit bootloaders need
+  them.
+
+* Paddings in executable text sections are now filled with trap instructions
+  (such as INT3) instead of being left as null bytes. This change improves
+  disassembler outputs because it now prints out trap instructions instead of
+  trying to decode 0x00 as an instruction. It also makes debugging of some type
+  of program easier because when the control reaches a padding, the program
+  immediately raises an error.
+
+* The following options are added: ``-M``, ``-Map``,
+  ``-compress-debug-sections``, ``-emit-relocs``,
+  ``-error-unresolved-symbols``, ``-exclude-libs``, ``-filter``,
+  ``-no-dynamic-linker``, ``-no-export-dynamic``, ``-no-fatal-warnings``,
+  ``-print-map``, ``-warn-unresolved-symbols``, ``-z nocopyreloc``,
+  ``-z notext``, ``-z rodynamic``
+
+
+COFF Improvements
+-----------------
+
+* Item 1.
+
+Contributors to lld 5.0
+=======================
+
+We had 63 individuals contribute to lld 5.0. Thank you so much!
+
+- Adrian McCarthy
+- Alberto Magni
+- Alexander Richardson
+- Andre Vieira
+- Andrew Ng
+- Anton Korobeynikov
+- Bob Haarman
+- David Blaikie
+- Davide Italiano
+- David L. Jones
+- Dmitry Mikulin
+- Ed Maste
+- Ed Schouten
+- Eric Beckmann
+- Eric Fiselier
+- Eugene Leviant
+- Evgeniy Stepanov
+- Galina Kistanova
+- George Rimar
+- Hans Wennborg
+- Igor Kudrin
+- Ismail Donmez
+- Jake Ehrlich
+- James Henderson
+- Joel Jones
+- Jon Chesterfield
+- Kamil Rytarowski
+- Kevin Enderby
+- Konstantin Zhuravlyov
+- Kyungwoo Lee
+- Leslie Zhai
+- Mark Kettenis
+- Martell Malone
+- Martin Storsjo
+- Meador Inge
+- Mehdi Amini
+- Michal Gorny
+- NAKAMURA Takumi
+- Paul Robinson
+- Pavel Labath
+- Petar Jovanovic
+- Peter Collingbourne
+- Peter Smith
+- Petr Hosek
+- Rafael Espindola
+- Reid Kleckner
+- Richard Smith
+- Robert Clarke
+- Rui Ueyama
+- Saleem Abdulrasool
+- Sam Clegg
+- Sean Eveson
+- Sean Silva
+- Shankar Easwaran
+- Shoaib Meenai
+- Simon Atanasyan
+- Simon Dardis
+- Simon Tatham
+- Sylvestre Ledru
+- Tom Stellard
+- Vitaly Buka
+- Yuka Takahashi
+- Zachary Turner
diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico
new file mode 100644 (file)
index 0000000..724ad6e
Binary files /dev/null and b/docs/_static/favicon.ico differ
diff --git a/docs/_templates/indexsidebar.html b/docs/_templates/indexsidebar.html
new file mode 100644 (file)
index 0000000..61968f2
--- /dev/null
@@ -0,0 +1,4 @@
+<h3>Bugs</h3>
+
+<p>lld bugs should be reported at the
+  LLVM <a href="http://llvm.org/bugs">Bugzilla</a>.</p>
diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html
new file mode 100644 (file)
index 0000000..519a24b
--- /dev/null
@@ -0,0 +1,12 @@
+{% extends "!layout.html" %}
+
+{% block extrahead %}
+<style type="text/css">
+  table.right { float: right; margin-left: 20px; }
+  table.right td { border: 1px solid #ccc; }
+</style>
+{% endblock %}
+
+{% block rootrellink %}
+  <li><a href="{{ pathto('index') }}">lld Home</a>&nbsp;|&nbsp;</li>
+{% endblock %}
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644 (file)
index 0000000..410b33e
--- /dev/null
@@ -0,0 +1,255 @@
+# -*- coding: utf-8 -*-
+#
+# lld documentation build configuration file.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+from datetime import date
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'lld'
+copyright = u'2011-%d, LLVM Project' % date.today().year
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short version.
+version = '5'
+# The full version, including alpha/beta/rc tags.
+release = '5'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%Y-%m-%d'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+show_authors = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'llvm-theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ["."]
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# If given, this must be the name of an image file (path relative to the
+# configuration directory) that is the favicon of the docs. Modern browsers use
+# this as icon for tabs, windows and bookmarks. It should be a Windows-style
+# icon file (.ico), which is 16x16 or 32x32 pixels large. Default: None.  The
+# image file will be copied to the _static directory of the output HTML, but
+# only if the file does not already exist there.
+html_favicon = '_static/favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%Y-%m-%d'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {'index': 'indexsidebar.html'}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {'index': 'index.html'}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'llddoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('contents', 'lld.tex', u'lld Documentation',
+   u'LLVM project', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('contents', 'lld', u'lld Documentation',
+     [u'LLVM project'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('contents', 'lld', u'lld Documentation',
+   u'LLVM project', 'lld', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# FIXME: Define intersphinx configration.
+intersphinx_mapping = {}
+
+
+# -- Options for extensions ----------------------------------------------------
+
+# Enable this if you want TODOs to show up in the generated documentation.
+todo_include_todos = True
diff --git a/docs/design.rst b/docs/design.rst
new file mode 100644 (file)
index 0000000..1e111f9
--- /dev/null
@@ -0,0 +1,421 @@
+.. _design:
+
+Linker Design
+=============
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+Introduction
+------------
+
+lld is a new generation of linker.  It is not "section" based like traditional
+linkers which mostly just interlace sections from multiple object files into the
+output file.  Instead, lld is based on "Atoms".  Traditional section based
+linking work well for simple linking, but their model makes advanced linking
+features difficult to implement.  Features like dead code stripping, reordering
+functions for locality, and C++ coalescing require the linker to work at a finer
+grain.
+
+An atom is an indivisible chunk of code or data.  An atom has a set of
+attributes, such as: name, scope, content-type, alignment, etc.  An atom also
+has a list of References.  A Reference contains: a kind, an optional offset, an
+optional addend, and an optional target atom.
+
+The Atom model allows the linker to use standard graph theory models for linking
+data structures.  Each atom is a node, and each Reference is an edge.  The
+feature of dead code stripping is implemented by following edges to mark all
+live atoms, and then delete the non-live atoms.
+
+
+Atom Model
+----------
+
+An atom is an indivisible chunk of code or data.  Typically each user written
+function or global variable is an atom.  In addition, the compiler may emit
+other atoms, such as for literal c-strings or floating point constants, or for
+runtime data structures like dwarf unwind info or pointers to initializers.
+
+A simple "hello world" object file would be modeled like this:
+
+.. image:: hello.png
+
+There are three atoms: main, a proxy for printf, and an anonymous atom
+containing the c-string literal "hello world".  The Atom "main" has two
+references. One is the call site for the call to printf, and the other is a
+reference for the instruction that loads the address of the c-string literal.
+
+There are only four different types of atoms:
+
+       * DefinedAtom
+               95% of all atoms.  This is a chunk of code or data
+
+       * UndefinedAtom
+          This is a place holder in object files for a reference to some atom
+          outside the translation unit.During core linking it is usually replaced
+          by (coalesced into) another Atom.
+
+       * SharedLibraryAtom
+               If a required symbol name turns out to be defined in a dynamic shared
+               library (and not some object file).  A SharedLibraryAtom is the
+               placeholder Atom used to represent that fact.
+
+               It is similar to an UndefinedAtom, but it also tracks information
+               about the associated shared library.
+
+       * AbsoluteAtom
+               This is for embedded support where some stuff is implemented in ROM at
+               some fixed address.  This atom has no content.  It is just an address
+               that the Writer needs to fix up any references to point to.
+
+
+File Model
+----------
+
+The linker views the input files as basically containers of Atoms and
+References, and just a few attributes of their own.  The linker works with three
+kinds of files: object files, static libraries, and dynamic shared libraries.
+Each kind of file has reader object which presents the file in the model
+expected by the linker.
+
+Object File
+~~~~~~~~~~~
+
+An object file is just a container of atoms.  When linking an object file, a
+reader is instantiated which parses the object file and instantiates a set of
+atoms representing all content in the .o file.  The linker adds all those atoms
+to a master graph.
+
+Static Library (Archive)
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the traditional unix static archive which is just a collection of object
+files with a "table of contents". When linking with a static library, by default
+nothing is added to the master graph of atoms. Instead, if after merging all
+atoms from object files into a master graph, if any "undefined" atoms are left
+remaining in the master graph, the linker reads the table of contents for each
+static library to see if any have the needed definitions. If so, the set of
+atoms from the specified object file in the static library is added to the
+master graph of atoms.
+
+Dynamic Library (Shared Object)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Dynamic libraries are different than object files and static libraries in that
+they don't directly add any content.  Their purpose is to check at build time
+that the remaining undefined references can be resolved at runtime, and provide
+a list of dynamic libraries (SO_NEEDED) that will be needed at runtime.  The way
+this is modeled in the linker is that a dynamic library contributes no atoms to
+the initial graph of atoms.  Instead, (like static libraries) if there are
+"undefined" atoms in the master graph of all atoms, then each dynamic library is
+checked to see if exports the required symbol. If so, a "shared library" atom is
+instantiated by the by the reader which the linker uses to replace the
+"undefined" atom.
+
+Linking Steps
+-------------
+
+Through the use of abstract Atoms, the core of linking is architecture
+independent and file format independent.  All command line parsing is factored
+out into a separate "options" abstraction which enables the linker to be driven
+with different command line sets.
+
+The overall steps in linking are:
+
+  #. Command line processing
+
+  #. Parsing input files
+
+  #. Resolving
+
+  #. Passes/Optimizations
+
+  #. Generate output file
+
+The Resolving and Passes steps are done purely on the master graph of atoms, so
+they have no notion of file formats such as mach-o or ELF.
+
+
+Input Files
+~~~~~~~~~~~
+
+Existing developer tools using different file formats for object files.
+A goal of lld is to be file format independent.  This is done
+through a plug-in model for reading object files. The lld::Reader is the base
+class for all object file readers.  A Reader follows the factory method pattern.
+A Reader instantiates an lld::File object (which is a graph of Atoms) from a
+given object file (on disk or in-memory).
+
+Every Reader subclass defines its own "options" class (for instance the mach-o
+Reader defines the class ReaderOptionsMachO).  This options class is the
+one-and-only way to control how the Reader operates when parsing an input file
+into an Atom graph.  For instance, you may want the Reader to only accept
+certain architectures.  The options class can be instantiated from command
+line options, or it can be subclassed and the ivars programmatically set.
+
+Resolving
+~~~~~~~~~
+
+The resolving step takes all the atoms' graphs from each object file and
+combines them into one master object graph.  Unfortunately, it is not as simple
+as appending the atom list from each file into one big list.  There are many
+cases where atoms need to be coalesced.  That is, two or more atoms need to be
+coalesced into one atom.  This is necessary to support: C language "tentative
+definitions", C++ weak symbols for templates and inlines defined in headers,
+replacing undefined atoms with actual definition atoms, and for merging copies
+of constants like c-strings and floating point constants.
+
+The linker support coalescing by-name and by-content. By-name is used for
+tentative definitions and weak symbols.  By-content is used for constant data
+that can be merged.
+
+The resolving process maintains some global linking "state", including a "symbol
+table" which is a map from llvm::StringRef to lld::Atom*.  With these data
+structures, the linker iterates all atoms in all input files. For each atom, it
+checks if the atom is named and has a global or hidden scope.  If so, the atom
+is added to the symbol table map.  If there already is a matching atom in that
+table, that means the current atom needs to be coalesced with the found atom, or
+it is a multiple definition error.
+
+When all initial input file atoms have been processed by the resolver, a scan is
+made to see if there are any undefined atoms in the graph.  If there are, the
+linker scans all libraries (both static and dynamic) looking for definitions to
+replace the undefined atoms.  It is an error if any undefined atoms are left
+remaining.
+
+Dead code stripping (if requested) is done at the end of resolving.  The linker
+does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main
+executable) and follows each references and marks each Atom that it visits as
+"live".  When done, all atoms not marked "live" are removed.
+
+The result of the Resolving phase is the creation of an lld::File object.  The
+goal is that the lld::File model is **the** internal representation
+throughout the linker. The file readers parse (mach-o, ELF, COFF) into an
+lld::File.  The file writers (mach-o, ELF, COFF) taken an lld::File and produce
+their file kind, and every Pass only operates on an lld::File.  This is not only
+a simpler, consistent model, but it enables the state of the linker to be dumped
+at any point in the link for testing purposes.
+
+
+Passes
+~~~~~~
+
+The Passes step is an open ended set of routines that each get a change to
+modify or enhance the current lld::File object. Some example Passes are:
+
+  * stub (PLT) generation
+
+  * GOT instantiation
+
+  * order_file optimization
+
+  * branch island generation
+
+  * branch shim generation
+
+  * Objective-C optimizations (Darwin specific)
+
+  * TLV instantiation (Darwin specific)
+
+  * DTrace probe processing (Darwin specific)
+
+  * compact unwind encoding (Darwin specific)
+
+
+Some of these passes are specific to Darwin's runtime environments.  But many of
+the passes are applicable to any OS (such as generating branch island for out of
+range branch instructions).
+
+The general structure of a pass is to iterate through the atoms in the current
+lld::File object, inspecting each atom and doing something.  For instance, the
+stub pass, looks for call sites to shared library atoms (e.g. call to printf).
+It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for
+each proxy atom needed, and these new atoms are added to the current lld::File
+object.  Next, all the noted call sites to shared library atoms have their
+References altered to point to the stub atom instead of the shared library atom.
+
+
+Generate Output File
+~~~~~~~~~~~~~~~~~~~~
+
+Once the passes are done, the output file writer is given current lld::File
+object.  The writer's job is to create the executable content file wrapper and
+place the content of the atoms into it.
+
+lld uses a plug-in model for writing output files. All concrete writers (e.g.
+ELF, mach-o, etc) are subclasses of the lld::Writer class.
+
+Unlike the Reader class which has just one method to instantiate an lld::File,
+the Writer class has multiple methods.  The crucial method is to generate the
+output file, but there are also methods which allow the Writer to contribute
+Atoms to the resolver and specify passes to run.
+
+An example of contributing
+atoms is that if the Writer knows a main executable is being linked and such
+an executable requires a specially named entry point (e.g. "_main"), the Writer
+can add an UndefinedAtom with that special name to the resolver.  This will
+cause the resolver to issue an error if that symbol is not defined.
+
+Sometimes a Writer supports lazily created symbols, such as names for the start
+of sections. To support this, the Writer can create a File object which vends
+no initial atoms, but does lazily supply atoms by name as needed.
+
+Every Writer subclass defines its own "options" class (for instance the mach-o
+Writer defines the class WriterOptionsMachO).  This options class is the
+one-and-only way to control how the Writer operates when producing an output
+file from an Atom graph.  For instance, you may want the Writer to optimize
+the output for certain OS versions, or strip local symbols, etc. The options
+class can be instantiated from command line options, or it can be subclassed
+and the ivars programmatically set.
+
+
+lld::File representations
+-------------------------
+
+Just as LLVM has three representations of its IR model, lld has two
+representations of its File/Atom/Reference model:
+
+ * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File).
+
+ * textual (in YAML)
+
+
+Textual representations in YAML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In designing a textual format we want something easy for humans to read and easy
+for the linker to parse.  Since an atom has lots of attributes most of which are
+usually just the default, we should define default values for every attribute so
+that those can be omitted from the text representation.  Here is the atoms for a
+simple hello world program expressed in YAML::
+
+  target-triple:   x86_64-apple-darwin11
+
+  atoms:
+      - name:    _main
+        scope:   global
+        type:    code
+        content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
+                   00, 00, 31, c0, 5d, c3 ]
+        fixups:
+        - offset: 07
+          kind:   pcrel32
+          target: 2
+        - offset: 0E
+          kind:   call32
+          target: _fprintf
+
+      - type:    c-string
+        content: [ 73, 5A, 00 ]
+
+  ...
+
+The biggest use for the textual format will be writing test cases.  Writing test
+cases in C is problematic because the compiler may vary its output over time for
+its own optimization reasons which my inadvertently disable or break the linker
+feature trying to be tested. By writing test cases in the linkers own textual
+format, we can exactly specify every attribute of every atom and thus target
+specific linker logic.
+
+The textual/YAML format follows the ReaderWriter patterns used in lld. The lld
+library comes with the classes: ReaderYAML and WriterYAML.
+
+
+Testing
+-------
+
+The lld project contains a test suite which is being built up as new code is
+added to lld.  All new lld functionality should have a tests added to the test
+suite.  The test suite is `lit <http://llvm.org/cmds/lit.html/>`_ driven.  Each
+test is a text file with comments telling lit how to run the test and check the
+result To facilitate testing, the lld project builds a tool called lld-core.
+This tool reads a YAML file (default from stdin), parses it into one or more
+lld::File objects in memory and then feeds those lld::File objects to the
+resolver phase.
+
+
+Resolver testing
+~~~~~~~~~~~~~~~~
+
+Basic testing is the "core linking" or resolving phase.  That is where the
+linker merges object files.  All test cases are written in YAML.  One feature of
+YAML is that it allows multiple "documents" to be encoding in one YAML stream.
+That means one text file can appear to the linker as multiple .o files - the
+normal case for the linker.
+
+Here is a simple example of a core linking test case. It checks that an
+undefined atom from one file will be replaced by a definition from another
+file::
+
+  # RUN: lld-core %s | FileCheck %s
+
+  #
+  # Test that undefined atoms are replaced with defined atoms.
+  #
+
+  ---
+  atoms:
+      - name:              foo
+        definition:        undefined
+  ---
+  atoms:
+      - name:              foo
+        scope:             global
+        type:              code
+  ...
+
+  # CHECK:       name:       foo
+  # CHECK:       scope:      global
+  # CHECK:       type:       code
+  # CHECK-NOT:   name:       foo
+  # CHECK:       ...
+
+
+Passes testing
+~~~~~~~~~~~~~~
+
+Since Passes just operate on an lld::File object, the lld-core tool has the
+option to run a particular pass (after resolving).  Thus, you can write a YAML
+test case with carefully crafted input to exercise areas of a Pass and the check
+the resulting lld::File object as represented in YAML.
+
+
+Design Issues
+-------------
+
+There are a number of open issues in the design of lld.  The plan is to wait and
+make these design decisions when we need to.
+
+
+Debug Info
+~~~~~~~~~~
+
+Currently, the lld model says nothing about debug info.  But the most popular
+debug format is DWARF and there is some impedance mismatch with the lld model
+and DWARF.  In lld there are just Atoms and only Atoms that need to be in a
+special section at runtime have an associated section.  Also, Atoms do not have
+addresses.  The way DWARF is spec'ed different parts of DWARF are supposed to go
+into specially named sections and the DWARF references function code by address.
+
+CPU and OS specific functionality
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently, lld has an abstract "Platform" that deals with any CPU or OS specific
+differences in linking.  We just keep adding virtual methods to the base
+Platform class as we find linking areas that might need customization.  At some
+point we'll need to structure this better.
+
+
+File Attributes
+~~~~~~~~~~~~~~~
+
+Currently, lld::File just has a path and a way to iterate its atoms. We will
+need to add more attributes on a File.  For example, some equivalent to the
+target triple.  There is also a number of cached or computed attributes that
+could make various Passes more efficient.  For instance, on Darwin there are a
+number of Objective-C optimizations that can be done by a Pass.  But it would
+improve the plain C case if the Objective-C optimization Pass did not have to
+scan all atoms looking for any Objective-C data structures.  This could be done
+if the lld::File object had an attribute that said if the file had any
+Objective-C data in it. The Resolving phase would then be required to "merge"
+that attribute as object files are added.
diff --git a/docs/development.rst b/docs/development.rst
new file mode 100644 (file)
index 0000000..ce91341
--- /dev/null
@@ -0,0 +1,45 @@
+.. _development:
+
+Development
+===========
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+lld is developed as part of the `LLVM <http://llvm.org>`_ project.
+
+Creating a Reader
+-----------------
+
+See the :ref:`Creating a Reader <Readers>` guide.
+
+
+Modifying the Driver
+--------------------
+
+See :doc:`Driver`.
+
+
+Debugging
+---------
+
+You can run lld with ``-mllvm -debug`` command line options to enable debugging
+printouts. If you want to enable debug information for some specific pass, you
+can run it with ``-mllvm '-debug-only=<pass>'``, where pass is a name used in
+the ``DEBUG_WITH_TYPE()`` macro.
+
+
+
+Documentation
+-------------
+
+The project documentation is written in reStructuredText and generated using the
+`Sphinx <http://sphinx.pocoo.org/>`_ documentation generator. For more
+information on writing documentation for the project, see the
+:ref:`sphinx_intro`.
+
+.. toctree::
+   :hidden:
+
+   Readers
+   Driver
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
new file mode 100644 (file)
index 0000000..97c3d1b
--- /dev/null
@@ -0,0 +1,106 @@
+.. _getting_started:
+
+Getting Started: Building and Running lld
+=========================================
+
+This page gives you the shortest path to checking out and building lld. If you
+run into problems, please file bugs in the `LLVM Bugzilla`__
+
+__ http://llvm.org/bugs/
+
+Building lld
+------------
+
+On Unix-like Systems
+~~~~~~~~~~~~~~~~~~~~
+
+1. Get the required tools.
+
+  * `CMake 2.8`_\+.
+  * make (or any build system CMake supports).
+  * `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required).
+
+    * If using Clang, you will also need `libc++`_.
+  * `Python 2.4`_\+ (not 3.x) for running tests.
+
+.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
+.. _Clang 3.1: http://clang.llvm.org/
+.. _libc++: http://libcxx.llvm.org/
+.. _Python 2.4: http://python.org/download/
+
+2. Check out LLVM::
+
+     $ cd path/to/llvm-project
+     $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
+
+3. Check out lld::
+
+     $ cd llvm/tools
+     $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+  * lld can also be checked out to ``path/to/llvm-project`` and built as an external
+    project.
+
+4. Build LLVM and lld::
+
+     $ cd path/to/llvm-build/llvm (out of source build required)
+     $ cmake -G "Unix Makefiles" path/to/llvm-project/llvm
+     $ make
+
+  * If you want to build with clang and it is not the default compiler or
+    it is installed in an alternate location, you'll need to tell the cmake tool
+    the location of the C and C++ compiler via CMAKE_C_COMPILER and
+    CMAKE_CXX_COMPILER. For example::
+
+        $ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ...
+
+5. Test::
+
+     $ make check-lld
+
+Using Visual Studio
+~~~~~~~~~~~~~~~~~~~
+
+#. Get the required tools.
+
+  * `CMake 2.8`_\+.
+  * `Visual Studio 12 (2013) or later`_ (required for C++11 support)
+  * `Python 2.4`_\+ (not 3.x) for running tests.
+
+.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
+.. _Visual Studio 12 (2013) or later: http://www.microsoft.com/visualstudio/11/en-us
+.. _Python 2.4: http://python.org/download/
+
+#. Check out LLVM::
+
+     $ cd path/to/llvm-project
+     $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
+
+#. Check out lld::
+
+     $ cd llvm/tools
+     $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+  * lld can also be checked out to ``path/to/llvm-project`` and built as an external
+    project.
+
+#. Generate Visual Studio project files::
+
+     $ cd path/to/llvm-build/llvm (out of source build required)
+     $ cmake -G "Visual Studio 11" path/to/llvm-project/llvm
+
+#. Build
+
+  * Open LLVM.sln in Visual Studio.
+  * Build the ``ALL_BUILD`` target.
+
+#. Test
+
+  * Build the ``lld-test`` target.
+
+More Information
+~~~~~~~~~~~~~~~~
+
+For more information on using CMake see the `LLVM CMake guide`_.
+
+.. _LLVM CMake guide: http://llvm.org/docs/CMake.html
diff --git a/docs/hello.png b/docs/hello.png
new file mode 100644 (file)
index 0000000..70df111
Binary files /dev/null and b/docs/hello.png differ
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..fbdade7
--- /dev/null
@@ -0,0 +1,179 @@
+LLD - The LLVM Linker
+=====================
+
+LLD is a linker from the LLVM project. That is a drop-in replacement
+for system linkers and runs much faster than them. It also provides
+features that are useful for toolchain developers.
+
+The linker supports ELF (Unix), PE/COFF (Windows) and Mach-O (macOS)
+in descending order of completeness. Internally, LLD consists of three
+different linkers. The ELF port is the one that will be described in
+this document. The PE/COFF port is almost complete except the lack of
+the Windows debug info (PDB) support. The Mach-O port is built based
+on a different architecture than the ELF or COFF ports. For the
+details about Mach-O, please read :doc:`AtomLLD`.
+
+Features
+--------
+
+- LLD is a drop-in replacement for the GNU linkers. That accepts the
+  same command line arguments and linker scripts as GNU.
+
+  We are currently working closely with the FreeBSD project to make
+  LLD default system linker in future versions of the operating
+  system, so we are serious about addressing compatibility issues. As
+  of February 2017, LLD is able to link the entire FreeBSD/amd64 base
+  system including the kernel. With a few work-in-progress patches it
+  can link approximately 95% of the ports collection on AMD64. For the
+  details, see `FreeBSD quarterly status report
+  <https://www.freebsd.org/news/status/report-2016-10-2016-12.html#Using-LLVM%27s-LLD-Linker-as-FreeBSD%27s-System-Linker>`_.
+
+- LLD is very fast. When you link a large program on a multicore
+  machine, you can expect that LLD runs more than twice as fast as GNU
+  gold linker. Your milage may vary, though.
+
+- It supports various CPUs/ABIs including x86-64, x86, x32, AArch64,
+  ARM, MIPS 32/64 big/little-endian, PowerPC, PowerPC 64 and AMDGPU.
+  Among these, x86-64 is the most well-supported target and have
+  reached production quality. AArch64 and MIPS seem decent too. x86
+  should be OK but not well tested yet. ARM support is being developed
+  actively.
+
+- It is always a cross-linker, meaning that it always supports all the
+  above targets however it was built. In fact, we don't provide a
+  build-time option to enable/disable each target. This should make it
+  easy to use our linker as part of a cross-compile toolchain.
+
+- You can embed LLD to your program to eliminate dependency to
+  external linkers. All you have to do is to construct object files
+  and command line arguments just like you would do to invoke an
+  external linker and then call the linker's main function,
+  ``lld::elf::link``, from your code.
+
+- It is small. We are using LLVM libObject library to read from object
+  files, so it is not completely a fair comparison, but as of February
+  2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold
+  consists of 198k lines of C++ code.
+
+- Link-time optimization (LTO) is supported by default. Essentially,
+  all you have to do to do LTO is to pass the ``-flto`` option to clang.
+  Then clang creates object files not in the native object file format
+  but in LLVM bitcode format. LLD reads bitcode object files, compile
+  them using LLVM and emit an output file. Because in this way LLD can
+  see the entire program, it can do the whole program optimization.
+
+- Some very old features for ancient Unix systems (pre-90s or even
+  before that) have been removed. Some default settings have been
+  tuned for the 21st century. For example, the stack is marked as
+  non-executable by default to tighten security.
+
+Performance
+-----------
+
+This is a link time comparison on a 2-socket 20-core 40-thread Xeon
+E5-2680 2.80 GHz machine with an SSD drive.
+
+LLD is much faster than the GNU linkers for large programs. That's
+fast for small programs too, but because the link time is short
+anyway, the difference is not very noticeable in that case.
+
+Note that this is just a benchmark result of our environment.
+Depending on number of available cores, available amount of memory or
+disk latency/throughput, your results may vary.
+
+============  ===========  ============  =============  ======
+Program       Output size  GNU ld        GNU gold [1]_  LLD
+ffmpeg dbg    91 MiB       1.59s         1.15s          0.78s
+mysqld dbg    157 MiB      7.09s         2.49s          1.31s
+clang dbg     1.45 GiB     86.76s        21.93s         8.38s
+chromium dbg  1.52 GiB     142.30s [2]_  40.86s         12.69s
+============  ===========  ============  =============  ======
+
+.. [1] With the ``--threads`` option to enable multi-threading support.
+
+.. [2] Since GNU ld doesn't support the ``-icf=all`` option, we
+       removed that from the command line for GNU ld. GNU ld would be
+       slower than this if it had that option support. For gold and
+       LLD, we use ``-icf=all``.
+
+Build
+-----
+
+If you have already checked out LLVM using SVN, you can check out LLD
+under ``tools`` directory just like you probably did for clang. For the
+details, see `Getting Started with the LLVM System
+<http://llvm.org/docs/GettingStarted.html>`_.
+
+If you haven't checkout out LLVM, the easiest way to build LLD is to
+checkout the entire LLVM projects/sub-projects from a git mirror and
+build that tree. You need `cmake` and of course a C++ compiler.
+
+.. code-block:: console
+
+  $ git clone https://github.com/llvm-project/llvm-project/
+  $ mkdir build
+  $ cd build
+  $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm
+  $ make install
+
+Using LLD
+---------
+
+LLD is installed as ``ld.lld``. On Unix, linkers are invoked by
+compiler drivers, so you are not expected to use that command
+directly. There are a few ways to tell compiler drivers to use ld.lld
+instead of the default linker.
+
+The easiest way to do that is to overwrite the default linker. After
+installing LLD to somewhere on your disk, you can create a symbolic
+link by doing ``ln -s /path/to/ld.lld /usr/bin/ld`` so that
+``/usr/bin/ld`` is resolved to LLD.
+
+If you don't want to change the system setting, you can use clang's
+``-fuse-ld`` option. In this way, you want to set ``-fuse-ld=lld`` to
+LDFLAGS when building your programs.
+
+LLD leaves its name and version number to a ``.comment`` section in an
+output. If you are in doubt whether you are successfully using LLD or
+not, run ``readelf --string-dump .comment <output-file>`` and examine the
+output. If the string "Linker: LLD" is included in the output, you are
+using LLD.
+
+History
+-------
+
+Here is a brief project history of the ELF and COFF ports.
+
+- May 2015: We decided to rewrite the COFF linker and did that.
+  Noticed that the new linker is much faster than the MSVC linker.
+
+- July 2015: The new ELF port was developed based on the COFF linker
+  architecture.
+
+- September 2015: The first patches to support MIPS and AArch64 landed.
+
+- October 2015: Succeeded to self-host the ELF port. We have noticed
+  that the linker was faster than the GNU linkers, but we weren't sure
+  at the time if we would be able to keep the gap as we would add more
+  features to the linker.
+
+- July 2016: Started working on improving the linker script support.
+
+- December 2016: Succeeded to build the entire FreeBSD base system
+  including the kernel. We had widen the performance gap against the
+  GNU linkers.
+
+Internals
+---------
+
+For the internals of the linker, please read :doc:`NewLLD`. It is a bit
+outdated but the fundamental concepts remain valid. We'll update the
+document soon.
+
+.. toctree::
+   :maxdepth: 1
+
+   NewLLD
+   AtomLLD
+   windows_support
+   ReleaseNotes
diff --git a/docs/llvm-theme/layout.html b/docs/llvm-theme/layout.html
new file mode 100644 (file)
index 0000000..0cd0918
--- /dev/null
@@ -0,0 +1,22 @@
+{#
+    sphinxdoc/layout.html
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    Sphinx layout template for the sphinxdoc theme.
+
+    :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+#}
+{% extends "basic/layout.html" %}
+
+{% block relbar1 %}
+<div class="logo">
+<a href="{{ pathto('index') }}"><img src="{{
+pathto("_static/logo.png", 1) }}" alt="LLVM Documentation"/></a>
+</div>
+{{ super() }}
+{% endblock %}
+
+{# put the sidebar before the body #}
+{% block sidebar1 %}{{ sidebar() }}{% endblock %}
+{% block sidebar2 %}{% endblock %}
diff --git a/docs/llvm-theme/static/contents.png b/docs/llvm-theme/static/contents.png
new file mode 100644 (file)
index 0000000..7fb8215
Binary files /dev/null and b/docs/llvm-theme/static/contents.png differ
diff --git a/docs/llvm-theme/static/llvm.css b/docs/llvm-theme/static/llvm.css
new file mode 100644 (file)
index 0000000..32802bb
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * sphinxdoc.css_t
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- sphinxdoc theme.  Originally created by
+ * Armin Ronacher for Werkzeug.
+ *
+ * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+                 'Verdana', sans-serif;
+    font-size: 14px;
+    letter-spacing: -0.01em;
+    line-height: 150%;
+    text-align: center;
+    background-color: #BFD1D4;
+    color: black;
+    padding: 0;
+    border: 1px solid #aaa;
+
+    margin: 0px 80px 0px 80px;
+    min-width: 740px;
+}
+
+div.logo {
+    background-color: white;
+    text-align: left;
+    padding: 10px 10px 15px 15px;
+}
+
+div.document {
+    background-color: white;
+    text-align: left;
+    background-image: url(contents.png);
+    background-repeat: repeat-x;
+}
+
+div.bodywrapper {
+    margin: 0 240px 0 0;
+    border-right: 1px solid #ccc;
+}
+
+div.body {
+    margin: 0;
+    padding: 0.5em 20px 20px 20px;
+}
+
+div.related {
+    font-size: 1em;
+}
+
+div.related ul {
+    background-image: url(navigation.png);
+    height: 2em;
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+}
+
+div.related ul li {
+    margin: 0;
+    padding: 0;
+    height: 2em;
+    float: left;
+}
+
+div.related ul li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+div.related ul li a {
+    margin: 0;
+    padding: 0 5px 0 5px;
+    line-height: 1.75em;
+    color: #EE9816;
+}
+
+div.related ul li a:hover {
+    color: #3CA8E7;
+}
+
+div.sphinxsidebarwrapper {
+    padding: 0;
+}
+
+div.sphinxsidebar {
+    margin: 0;
+    padding: 0.5em 15px 15px 0;
+    width: 210px;
+    float: right;
+    font-size: 1em;
+    text-align: left;
+}
+
+div.sphinxsidebar h3, div.sphinxsidebar h4 {
+    margin: 1em 0 0.5em 0;
+    font-size: 1em;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border: 1px solid #86989B;
+    background-color: #AFC1C4;
+}
+
+div.sphinxsidebar h3 a {
+    color: white;
+}
+
+div.sphinxsidebar ul {
+    padding-left: 1.5em;
+    margin-top: 7px;
+    padding: 0;
+    line-height: 130%;
+}
+
+div.sphinxsidebar ul ul {
+    margin-left: 20px;
+}
+
+div.footer {
+    background-color: #E3EFF1;
+    color: #86989B;
+    padding: 3px 8px 3px 0;
+    clear: both;
+    font-size: 0.8em;
+    text-align: right;
+}
+
+div.footer a {
+    color: #86989B;
+    text-decoration: underline;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+p {
+    margin: 0.8em 0 0.5em 0;
+}
+
+a {
+    color: #CA7900;
+    text-decoration: none;
+}
+
+a:hover {
+    color: #2491CF;
+}
+
+div.body a {
+    text-decoration: underline;
+}
+
+h1 {
+    margin: 0;
+    padding: 0.7em 0 0.3em 0;
+    font-size: 1.5em;
+    color: #11557C;
+}
+
+h2 {
+    margin: 1.3em 0 0.2em 0;
+    font-size: 1.35em;
+    padding: 0;
+}
+
+h3 {
+    margin: 1em 0 -0.3em 0;
+    font-size: 1.2em;
+}
+
+div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
+    color: black!important;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+    display: none;
+    margin: 0 0 0 0.3em;
+    padding: 0 0.2em 0 0.2em;
+    color: #aaa!important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+    display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+    color: #777;
+    background-color: #eee;
+}
+
+a.headerlink {
+    color: #c60f0f!important;
+    font-size: 1em;
+    margin-left: 6px;
+    padding: 0 4px 0 4px;
+    text-decoration: none!important;
+}
+
+a.headerlink:hover {
+    background-color: #ccc;
+    color: white!important;
+}
+
+cite, code, tt {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.01em;
+}
+
+tt {
+    background-color: #f2f2f2;
+    border-bottom: 1px solid #ddd;
+    color: #333;
+}
+
+tt.descname, tt.descclassname, tt.xref {
+    border: 0;
+}
+
+hr {
+    border: 1px solid #abc;
+    margin: 2em;
+}
+
+a tt {
+    border: 0;
+    color: #CA7900;
+}
+
+a tt:hover {
+    color: #2491CF;
+}
+
+pre {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.015em;
+    line-height: 120%;
+    padding: 0.5em;
+    border: 1px solid #ccc;
+    background-color: #f8f8f8;
+}
+
+pre a {
+    color: inherit;
+    text-decoration: underline;
+}
+
+td.linenos pre {
+    padding: 0.5em 0;
+}
+
+div.quotebar {
+    background-color: #f8f8f8;
+    max-width: 250px;
+    float: right;
+    padding: 2px 7px;
+    border: 1px solid #ccc;
+}
+
+div.topic {
+    background-color: #f8f8f8;
+}
+
+table {
+    border-collapse: collapse;
+    margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+    padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+div.admonition, div.warning {
+    font-size: 0.9em;
+    margin: 1em 0 1em 0;
+    border: 1px solid #86989B;
+    background-color: #f7f7f7;
+    padding: 0;
+}
+
+div.admonition p, div.warning p {
+    margin: 0.5em 1em 0.5em 1em;
+    padding: 0;
+}
+
+div.admonition pre, div.warning pre {
+    margin: 0.4em 1em 0.4em 1em;
+}
+
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+    margin: 0;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border-bottom: 1px solid #86989B;
+    font-weight: bold;
+    background-color: #AFC1C4;
+}
+
+div.warning {
+    border: 1px solid #940000;
+}
+
+div.warning p.admonition-title {
+    background-color: #CF0000;
+    border-bottom-color: #940000;
+}
+
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
+    margin: 0.1em 0.5em 0.5em 3em;
+    padding: 0;
+}
+
+div.versioninfo {
+    margin: 1em 0 0 0;
+    border: 1px solid #ccc;
+    background-color: #DDEAF0;
+    padding: 8px;
+    line-height: 1.3em;
+    font-size: 0.9em;
+}
+
+.viewcode-back {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+                 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
diff --git a/docs/llvm-theme/static/logo.png b/docs/llvm-theme/static/logo.png
new file mode 100644 (file)
index 0000000..4fc8990
Binary files /dev/null and b/docs/llvm-theme/static/logo.png differ
diff --git a/docs/llvm-theme/static/navigation.png b/docs/llvm-theme/static/navigation.png
new file mode 100644 (file)
index 0000000..1081dc1
Binary files /dev/null and b/docs/llvm-theme/static/navigation.png differ
diff --git a/docs/llvm-theme/theme.conf b/docs/llvm-theme/theme.conf
new file mode 100644 (file)
index 0000000..330fc92
--- /dev/null
@@ -0,0 +1,4 @@
+[theme]
+inherit = basic
+stylesheet = llvm.css
+pygments_style = friendly
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644 (file)
index 0000000..8471252
--- /dev/null
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+       set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+       set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+       set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+       :help
+       echo.Please use `make ^<target^>` where ^<target^> is one of
+       echo.  html       to make standalone HTML files
+       echo.  dirhtml    to make HTML files named index.html in directories
+       echo.  singlehtml to make a single large HTML file
+       echo.  pickle     to make pickle files
+       echo.  json       to make JSON files
+       echo.  htmlhelp   to make HTML files and a HTML help project
+       echo.  qthelp     to make HTML files and a qthelp project
+       echo.  devhelp    to make HTML files and a Devhelp project
+       echo.  epub       to make an epub
+       echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+       echo.  text       to make text files
+       echo.  man        to make manual pages
+       echo.  texinfo    to make Texinfo files
+       echo.  gettext    to make PO message catalogs
+       echo.  changes    to make an overview over all changed/added/deprecated items
+       echo.  linkcheck  to check all external links for integrity
+       echo.  doctest    to run all doctests embedded in the documentation if enabled
+       goto end
+)
+
+if "%1" == "clean" (
+       for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+       del /q /s %BUILDDIR%\*
+       goto end
+)
+
+if "%1" == "html" (
+       %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+       goto end
+)
+
+if "%1" == "dirhtml" (
+       %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+       goto end
+)
+
+if "%1" == "singlehtml" (
+       %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+       goto end
+)
+
+if "%1" == "pickle" (
+       %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can process the pickle files.
+       goto end
+)
+
+if "%1" == "json" (
+       %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can process the JSON files.
+       goto end
+)
+
+if "%1" == "htmlhelp" (
+       %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+       goto end
+)
+
+if "%1" == "qthelp" (
+       %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+       echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp
+       echo.To view the help file:
+       echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc
+       goto end
+)
+
+if "%1" == "devhelp" (
+       %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished.
+       goto end
+)
+
+if "%1" == "epub" (
+       %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The epub file is in %BUILDDIR%/epub.
+       goto end
+)
+
+if "%1" == "latex" (
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+       goto end
+)
+
+if "%1" == "text" (
+       %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The text files are in %BUILDDIR%/text.
+       goto end
+)
+
+if "%1" == "man" (
+       %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The manual pages are in %BUILDDIR%/man.
+       goto end
+)
+
+if "%1" == "texinfo" (
+       %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+       goto end
+)
+
+if "%1" == "gettext" (
+       %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+       goto end
+)
+
+if "%1" == "changes" (
+       %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.The overview file is in %BUILDDIR%/changes.
+       goto end
+)
+
+if "%1" == "linkcheck" (
+       %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+       goto end
+)
+
+if "%1" == "doctest" (
+       %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+       if errorlevel 1 exit /b 1
+       echo.
+       echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+       goto end
+)
+
+:end
diff --git a/docs/open_projects.rst b/docs/open_projects.rst
new file mode 100644 (file)
index 0000000..eeb9f9f
--- /dev/null
@@ -0,0 +1,11 @@
+.. _open_projects:
+
+Open Projects
+=============
+
+.. include:: ../include/lld/Core/TODO.txt
+
+Documentation TODOs
+~~~~~~~~~~~~~~~~~~~
+
+.. todolist::
diff --git a/docs/sphinx_intro.rst b/docs/sphinx_intro.rst
new file mode 100644 (file)
index 0000000..6845bc8
--- /dev/null
@@ -0,0 +1,147 @@
+.. _sphinx_intro:
+
+Sphinx Introduction for LLVM Developers
+=======================================
+
+This document is intended as a short and simple introduction to the Sphinx
+documentation generation system for LLVM developers.
+
+Quickstart
+----------
+
+To get started writing documentation, you will need to:
+
+ 1. Have the Sphinx tools :ref:`installed <installing_sphinx>`.
+
+ 2. Understand how to :ref:`build the documentation
+    <building_the_documentation>`.
+
+ 3. Start :ref:`writing documentation <writing_documentation>`!
+
+.. _installing_sphinx:
+
+Installing Sphinx
+~~~~~~~~~~~~~~~~~
+
+You should be able to install Sphinx using the standard Python package
+installation tool ``easy_install``, as follows::
+
+  $ sudo easy_install sphinx
+  Searching for sphinx
+  Reading http://pypi.python.org/simple/sphinx/
+  Reading http://sphinx.pocoo.org/
+  Best match: Sphinx 1.1.3
+  ... more lines here ..
+
+If you do not have root access (or otherwise want to avoid installing Sphinx in
+system directories) see the section on :ref:`installing_sphinx_in_a_venv` .
+
+If you do not have the ``easy_install`` tool on your system, you should be able
+to install it using:
+
+  Linux
+    Use your distribution's standard package management tool to install it,
+    i.e., ``apt-get install easy_install`` or ``yum install easy_install``.
+
+  Mac OS X
+    All modern Mac OS X systems come with ``easy_install`` as part of the base
+    system.
+
+  Windows
+    See the `setuptools <http://pypi.python.org/pypi/setuptools>`_ package web
+    page for instructions.
+
+
+.. _building_the_documentation:
+
+Building the documentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to build the documentation, all you should need to do is change to the
+``docs`` directory and invoke make as follows::
+
+  $ cd path/to/project/docs
+  $ make html
+
+Note that on Windows there is a ``make.bat`` command in the docs directory which
+supplies the same interface as the ``Makefile``.
+
+That command will invoke ``sphinx-build`` with the appropriate options for the
+project, and generate the HTML documentation in a ``_build`` subdirectory. You
+can browse it starting from the index page by visiting
+``_build/html/index.html``.
+
+Sphinx supports a wide variety of generation formats (including LaTeX, man
+pages, and plain text). The ``Makefile`` includes a number of convenience
+targets for invoking ``sphinx-build`` appropriately, the common ones are:
+
+  make html
+    Generate the HTML output.
+
+  make latexpdf
+    Generate LaTeX documentation and convert to a PDF.
+
+  make man
+    Generate man pages.
+
+
+.. _writing_documentation:
+
+Writing documentation
+~~~~~~~~~~~~~~~~~~~~~
+
+The documentation itself is written in the reStructuredText (ReST) format, and Sphinx
+defines additional tags to support features like cross-referencing.
+
+The ReST format itself is organized around documents mostly being readable
+plaintext documents. You should generally be able to write new documentation
+easily just by following the style of the existing documentation.
+
+If you want to understand the formatting of the documents more, the best place
+to start is Sphinx's own `ReST Primer <http://sphinx.pocoo.org/rest.html>`_.
+
+
+Learning More
+-------------
+
+If you want to learn more about the Sphinx system, the best place to start is
+the Sphinx documentation itself, available `here
+<http://sphinx.pocoo.org/contents.html>`_.
+
+
+.. _installing_sphinx_in_a_venv:
+
+Installing Sphinx in a Virtual Environment
+------------------------------------------
+
+Most Python developers prefer to work with tools inside a *virtualenv* (virtual
+environment) instance, which functions as an application sandbox. This avoids
+polluting your system installation with different packages used by various
+projects (and ensures that dependencies for different packages don't conflict
+with one another). Of course, you need to first have the virtualenv software
+itself which generally would be installed at the system level::
+
+  $ sudo easy_install virtualenv
+
+but after that you no longer need to install additional packages in the system
+directories.
+
+Once you have the *virtualenv* tool itself installed, you can create a
+virtualenv for Sphinx using::
+
+  $ virtualenv ~/my-sphinx-install
+  New python executable in /Users/dummy/my-sphinx-install/bin/python
+  Installing setuptools............done.
+  Installing pip...............done.
+
+  $ ~/my-sphinx-install/bin/easy_install sphinx
+  ... install messages here ...
+
+and from now on you can "activate" the *virtualenv* using::
+
+  $ source ~/my-sphinx-install/bin/activate
+
+which will change your PATH to ensure the sphinx-build tool from inside the
+virtual environment will be used. See the `virtualenv website
+<http://www.virtualenv.org/en/latest/index.html>`_ for more information on using
+virtual environments.
diff --git a/docs/windows_support.rst b/docs/windows_support.rst
new file mode 100644 (file)
index 0000000..6b06d29
--- /dev/null
@@ -0,0 +1,91 @@
+.. raw:: html
+
+  <style type="text/css">
+    .none { background-color: #FFCCCC }
+    .partial { background-color: #FFFF99 }
+    .good { background-color: #CCFF99 }
+  </style>
+
+.. role:: none
+.. role:: partial
+.. role:: good
+
+===============
+Windows support
+===============
+
+LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with
+``-flavor link``, the driver for Windows operating system is used to parse
+command line options, and it drives further linking processes. LLD accepts
+almost all command line options that the linker shipped with Microsoft Visual
+C++ (link.exe) supports.
+
+The current status is that LLD can link itself on Windows x86/x64
+using Visual C++ 2013 as the compiler.
+
+Development status
+==================
+
+Driver
+  :good:`Mostly done`. Some exotic command line options that are not usually
+  used for application develompent, such as ``/DRIVER``, are not supported.
+
+Linking against DLL
+  :good:`Done`. LLD can read import libraries needed to link against DLL. Both
+  export-by-name and export-by-ordinal are supported.
+
+Linking against static library
+  :good:`Done`. The format of static library (.lib) on Windows is actually the
+  same as on Unix (.a). LLD can read it.
+
+Creating DLL
+  :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported
+  functions can be specified either via command line (``/EXPORT``) or via
+  module-definition file (.def). Both export-by-name and export-by-ordinal are
+  supported.
+
+Windows resource files support
+  :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF
+  file using LLVM's Object library.
+
+Safe Structured Exception Handler (SEH)
+  :good:`Done` for both x86 and x64.
+
+Module-definition file
+  :partial:`Partially done`. LLD currently recognizes these directives:
+  ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``.
+
+Debug info
+  :none:`No progress has been made`. Microsoft linker can interpret the CodeGen
+  debug info (old-style debug info) and PDB to emit an .pdb file. LLD doesn't
+  support neither.
+
+
+Building LLD
+============
+
+Using Visual Studio IDE/MSBuild
+-------------------------------
+
+1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
+#. run ``cmake -G "Visual Studio 12" <llvm-source-dir>`` from VS command prompt,
+#. open LLVM.sln with Visual Studio, and
+#. build ``lld`` target in ``lld executables`` folder
+
+Alternatively, you can use msbuild if you don't like to work in an IDE::
+
+  msbuild LLVM.sln /m /target:"lld executables\lld"
+
+MSBuild.exe had been shipped as a component of the .NET framework, but since
+2013 it's part of Visual Studio. You can find it at "C:\\Program Files
+(x86)\\msbuild".
+
+You can build LLD as a 64 bit application. To do that, open VS2013 x64 command
+prompt and run cmake for "Visual Studio 12 Win64" target.
+
+Using Ninja
+-----------
+
+1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
+#. run ``cmake -G ninja <llvm-source-dir>`` from VS command prompt,
+#. run ``ninja lld``
diff --git a/include/lld/Config/Version.h b/include/lld/Config/Version.h
new file mode 100644 (file)
index 0000000..1cec3cc
--- /dev/null
@@ -0,0 +1,25 @@
+//===- lld/Config/Version.h - LLD Version Number ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a version-related utility function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_VERSION_H
+#define LLD_VERSION_H
+
+#include "lld/Config/Version.inc"
+#include "llvm/ADT/StringRef.h"
+
+namespace lld {
+/// \brief Retrieves a string representing the complete lld version.
+std::string getLLDVersion();
+}
+
+#endif // LLD_VERSION_H
diff --git a/include/lld/Config/Version.inc.in b/include/lld/Config/Version.inc.in
new file mode 100644 (file)
index 0000000..2789a5c
--- /dev/null
@@ -0,0 +1,6 @@
+#define LLD_VERSION @LLD_VERSION@
+#define LLD_VERSION_STRING "@LLD_VERSION@"
+#define LLD_VERSION_MAJOR @LLD_VERSION_MAJOR@
+#define LLD_VERSION_MINOR @LLD_VERSION_MINOR@
+#define LLD_REVISION_STRING "@LLD_REVISION@"
+#define LLD_REPOSITORY_STRING "@LLD_REPOSITORY@"
diff --git a/include/lld/Core/AbsoluteAtom.h b/include/lld/Core/AbsoluteAtom.h
new file mode 100644 (file)
index 0000000..ed25297
--- /dev/null
@@ -0,0 +1,43 @@
+//===- Core/AbsoluteAtom.h - An absolute Atom -----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ABSOLUTE_ATOM_H
+#define LLD_CORE_ABSOLUTE_ATOM_H
+
+#include "lld/Core/Atom.h"
+
+namespace lld {
+
+/// An AbsoluteAtom has no content.
+/// It exists to represent content at fixed addresses in memory.
+class AbsoluteAtom : public Atom {
+public:
+
+  virtual uint64_t value() const = 0;
+
+  /// scope - The visibility of this atom to other atoms.  C static functions
+  /// have scope scopeTranslationUnit.  Regular C functions have scope
+  /// scopeGlobal.  Functions compiled with visibility=hidden have scope
+  /// scopeLinkageUnit so they can be see by other atoms being linked but not
+  /// by the OS loader.
+  virtual Scope scope() const = 0;
+
+  static bool classof(const Atom *a) {
+    return a->definition() == definitionAbsolute;
+  }
+
+  static bool classof(const AbsoluteAtom *) { return true; }
+
+protected:
+  AbsoluteAtom() : Atom(definitionAbsolute) {}
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_ABSOLUTE_ATOM_H
diff --git a/include/lld/Core/ArchiveLibraryFile.h b/include/lld/Core/ArchiveLibraryFile.h
new file mode 100644 (file)
index 0000000..2c736e7
--- /dev/null
@@ -0,0 +1,47 @@
+//===- Core/ArchiveLibraryFile.h - Models static library ------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H
+#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H
+
+#include "lld/Core/File.h"
+#include <set>
+
+namespace lld {
+
+///
+/// The ArchiveLibraryFile subclass of File is used to represent unix
+/// static library archives.  These libraries provide no atoms to the
+/// initial set of atoms linked.  Instead, when the Resolver will query
+/// ArchiveLibraryFile instances for specific symbols names using the
+/// find() method.  If the archive contains an object file which has a
+/// DefinedAtom whose scope is not translationUnit, then that entire
+/// object file File is returned.
+///
+class ArchiveLibraryFile : public File {
+public:
+  static bool classof(const File *f) {
+    return f->kind() == kindArchiveLibrary;
+  }
+
+  /// Check if any member of the archive contains an Atom with the
+  /// specified name and return the File object for that member, or nullptr.
+  virtual File *find(StringRef name) = 0;
+
+  virtual std::error_code
+  parseAllMembers(std::vector<std::unique_ptr<File>> &result) = 0;
+
+protected:
+  /// only subclasses of ArchiveLibraryFile can be instantiated
+  ArchiveLibraryFile(StringRef path) : File(path, kindArchiveLibrary) {}
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H
diff --git a/include/lld/Core/Atom.h b/include/lld/Core/Atom.h
new file mode 100644 (file)
index 0000000..156a5d4
--- /dev/null
@@ -0,0 +1,131 @@
+//===- Core/Atom.h - A node in linking graph --------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ATOM_H
+#define LLD_CORE_ATOM_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lld {
+
+class File;
+
+template<typename T>
+class OwningAtomPtr;
+
+///
+/// The linker has a Graph Theory model of linking. An object file is seen
+/// as a set of Atoms with References to other Atoms.  Each Atom is a node
+/// and each Reference is an edge. An Atom can be a DefinedAtom which has
+/// content or a UndefinedAtom which is a placeholder and represents an
+/// undefined symbol (extern declaration).
+///
+class Atom {
+  template<typename T> friend class OwningAtomPtr;
+
+public:
+  /// Whether this atom is defined or a proxy for an undefined symbol
+  enum Definition {
+    definitionRegular,      ///< Normal C/C++ function or global variable.
+    definitionAbsolute,     ///< Asm-only (foo = 10). Not tied to any content.
+    definitionUndefined,    ///< Only in .o files to model reference to undef.
+    definitionSharedLibrary ///< Only in shared libraries to model export.
+  };
+
+  /// The scope in which this atom is acessible to other atoms.
+  enum Scope {
+    scopeTranslationUnit,  ///< Accessible only to atoms in the same translation
+                           ///  unit (e.g. a C static).
+    scopeLinkageUnit,      ///< Accessible to atoms being linked but not visible
+                           ///  to runtime loader (e.g. visibility=hidden).
+    scopeGlobal            ///< Accessible to all atoms and visible to runtime
+                           ///  loader (e.g. visibility=default).
+  };
+
+  /// file - returns the File that produced/owns this Atom
+  virtual const File& file() const = 0;
+
+  /// name - The name of the atom. For a function atom, it is the (mangled)
+  /// name of the function.
+  virtual StringRef name() const = 0;
+
+  /// definition - Whether this atom is a definition or represents an undefined
+  /// symbol.
+  Definition definition() const { return _definition; }
+
+  static bool classof(const Atom *a) { return true; }
+
+protected:
+  /// Atom is an abstract base class.  Only subclasses can access constructor.
+  explicit Atom(Definition def) : _definition(def) {}
+
+  /// The memory for Atom objects is always managed by the owning File
+  /// object.  Therefore, no one but the owning File object should call
+  /// delete on an Atom.  In fact, some File objects may bulk allocate
+  /// an array of Atoms, so they cannot be individually deleted by anyone.
+  virtual ~Atom() = default;
+
+private:
+  Definition _definition;
+};
+
+/// Class which owns an atom pointer and runs the atom destructor when the
+/// owning pointer goes out of scope.
+template<typename T>
+class OwningAtomPtr {
+private:
+  OwningAtomPtr(const OwningAtomPtr &) = delete;
+  void operator=(const OwningAtomPtr &) = delete;
+
+public:
+  OwningAtomPtr() = default;
+  OwningAtomPtr(T *atom) : atom(atom) { }
+
+  ~OwningAtomPtr() {
+    if (atom)
+      runDestructor(atom);
+  }
+
+  void runDestructor(Atom *atom) {
+    atom->~Atom();
+  }
+
+  OwningAtomPtr(OwningAtomPtr &&ptr) : atom(ptr.atom) {
+    ptr.atom = nullptr;
+  }
+
+  void operator=(OwningAtomPtr&& ptr) {
+    if (atom)
+      runDestructor(atom);
+    atom = ptr.atom;
+    ptr.atom = nullptr;
+  }
+
+  T *const &get() const {
+    return atom;
+  }
+
+  T *&get() {
+    return atom;
+  }
+
+  T *release() {
+    auto *v = atom;
+    atom = nullptr;
+    return v;
+  }
+
+private:
+  T *atom = nullptr;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_ATOM_H
diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h
new file mode 100644 (file)
index 0000000..7f623d2
--- /dev/null
@@ -0,0 +1,374 @@
+//===- Core/DefinedAtom.h - An Atom with content --------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_DEFINED_ATOM_H
+#define LLD_CORE_DEFINED_ATOM_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace lld {
+class File;
+
+/// \brief The fundamental unit of linking.
+///
+/// A C function or global variable is an atom.  An atom has content and
+/// attributes. The content of a function atom is the instructions that
+/// implement the function.  The content of a global variable atom is its
+/// initial bytes.
+///
+/// Here are some example attribute sets for common atoms. If a particular
+/// attribute is not listed, the default values are:  definition=regular,
+/// sectionChoice=basedOnContent, scope=translationUnit, merge=no,
+/// deadStrip=normal, interposable=no
+///
+///  C function:  void foo() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global
+///
+///  C static function:  staic void func() {} <br>
+///    name=func, type=code, perm=r_x
+///
+///  C global variable:  int count = 1; <br>
+///    name=count, type=data, perm=rw_, scope=global
+///
+///  C tentative definition:  int bar; <br>
+///    name=bar, type=zerofill, perm=rw_, scope=global,
+///    merge=asTentative, interposable=yesAndRuntimeWeak
+///
+///  Uninitialized C static variable:  static int stuff; <br>
+///    name=stuff, type=zerofill, perm=rw_
+///
+///  Weak C function:  __attribute__((weak)) void foo() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global, merge=asWeak
+///
+///  Hidden C function:  __attribute__((visibility("hidden"))) void foo() {}<br>
+///    name=foo, type=code, perm=r_x, scope=linkageUnit
+///
+///  No-dead-strip function:  __attribute__((used)) void foo() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global, deadStrip=never
+///
+///  Non-inlined C++ inline method:  inline void Foo::doit() {} <br>
+///    name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
+///    mergeDupes=asWeak
+///
+///  Non-inlined C++ inline method whose address is taken:
+///     inline void Foo::doit() {} <br>
+///    name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
+///    mergeDupes=asAddressedWeak
+///
+///  literal c-string:  "hello" <br>
+///    name="" type=cstring, perm=r__, scope=linkageUnit
+///
+///  literal double:  1.234 <br>
+///    name="" type=literal8, perm=r__, scope=linkageUnit
+///
+///  constant:  { 1,2,3 } <br>
+///    name="" type=constant, perm=r__, scope=linkageUnit
+///
+///  Pointer to initializer function:  <br>
+///    name="" type=initializer, perm=rw_l,
+///    sectionChoice=customRequired
+///
+///  C function place in custom section:  __attribute__((section("__foo")))
+///                                       void foo() {} <br>
+///    name=foo, type=code, perm=r_x, scope=global,
+///    sectionChoice=customRequired, customSectionName=__foo
+///
+class DefinedAtom : public Atom {
+public:
+  enum Interposable {
+    interposeNo,            // linker can directly bind uses of this atom
+    interposeYes,           // linker must indirect (through GOT) uses
+    interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
+                               // linked image
+  };
+
+  enum Merge {
+    mergeNo,                // Another atom with same name is error
+    mergeAsTentative,       // Is ANSI C tentative definition, can be coalesced
+    mergeAsWeak,            // Is C++ inline definition that was not inlined,
+                            // but address was not taken, so atom can be hidden
+                            // by linker
+    mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose
+                               // address was taken.
+    mergeSameNameAndSize,   // Another atom with different size is error
+    mergeByLargestSection,  // Choose an atom whose section is the largest.
+    mergeByContent,         // Merge with other constants with same content.
+  };
+
+  enum ContentType {
+    typeUnknown,            // for use with definitionUndefined
+    typeMachHeader,         // atom representing mach_header [Darwin]
+    typeCode,               // executable code
+    typeResolver,           // function which returns address of target
+    typeBranchIsland,       // linker created for large binaries
+    typeBranchShim,         // linker created to switch thumb mode
+    typeStub,               // linker created for calling external function
+    typeStubHelper,         // linker created for initial stub binding
+    typeConstant,           // a read-only constant
+    typeCString,            // a zero terminated UTF8 C string
+    typeUTF16String,        // a zero terminated UTF16 string
+    typeCFI,                // a FDE or CIE from dwarf unwind info
+    typeLSDA,               // extra unwinding info
+    typeLiteral4,           // a four-btye read-only constant
+    typeLiteral8,           // an eight-btye read-only constant
+    typeLiteral16,          // a sixteen-btye read-only constant
+    typeData,               // read-write data
+    typeDataFast,           // allow data to be quickly accessed
+    typeZeroFill,           // zero-fill data
+    typeZeroFillFast,       // allow zero-fill data to be quicky accessed
+    typeConstData,          // read-only data after dynamic linker is done
+    typeObjC1Class,         // ObjC1 class [Darwin]
+    typeLazyPointer,        // pointer through which a stub jumps
+    typeLazyDylibPointer,   // pointer through which a stub jumps [Darwin]
+    typeNonLazyPointer,     // pointer to external symbol
+    typeCFString,           // NS/CFString object [Darwin]
+    typeGOT,                // pointer to external symbol
+    typeInitializerPtr,     // pointer to initializer function
+    typeTerminatorPtr,      // pointer to terminator function
+    typeCStringPtr,         // pointer to UTF8 C string [Darwin]
+    typeObjCClassPtr,       // pointer to ObjC class [Darwin]
+    typeObjC2CategoryList,  // pointers to ObjC category [Darwin]
+    typeObjCImageInfo,      // pointer to ObjC class [Darwin]
+    typeObjCMethodList,     // pointer to ObjC method list [Darwin]
+    typeDTraceDOF,          // runtime data for Dtrace [Darwin]
+    typeInterposingTuples,  // tuples of interposing info for dyld [Darwin]
+    typeTempLTO,            // temporary atom for bitcode reader
+    typeCompactUnwindInfo,  // runtime data for unwinder [Darwin]
+    typeProcessedUnwindInfo,// compressed compact unwind info [Darwin]
+    typeThunkTLV,           // thunk used to access a TLV [Darwin]
+    typeTLVInitialData,     // initial data for a TLV [Darwin]
+    typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
+    typeTLVInitializerPtr,  // pointer to thread local initializer [Darwin]
+    typeDSOHandle,          // atom representing DSO handle [Darwin]
+    typeSectCreate,         // Created via the -sectcreate option [Darwin]
+  };
+
+  // Permission bits for atoms and segments. The order of these values are
+  // important, because the layout pass may sort atoms by permission if other
+  // attributes are the same.
+  enum ContentPermissions {
+    perm___  = 0,           // mapped as unaccessible
+    permR__  = 8,           // mapped read-only
+    permRW_  = 8 + 2,       // mapped readable and writable
+    permRW_L = 8 + 2 + 1,   // initially mapped r/w, then made read-only
+                            // loader writable
+    permR_X  = 8 + 4,       // mapped readable and executable
+    permRWX  = 8 + 2 + 4,   // mapped readable and writable and executable
+    permUnknown = 16        // unknown or invalid permissions
+  };
+
+  enum SectionChoice {
+    sectionBasedOnContent,  // linker infers final section based on content
+    sectionCustomPreferred, // linker may place in specific section
+    sectionCustomRequired   // linker must place in specific section
+  };
+
+  enum DeadStripKind {
+    deadStripNormal,        // linker may dead strip this atom
+    deadStripNever,         // linker must never dead strip this atom
+    deadStripAlways         // linker must remove this atom if unused
+  };
+
+  enum DynamicExport {
+    /// \brief The linker may or may not export this atom dynamically depending
+    ///   on the output type and other context of the link.
+    dynamicExportNormal,
+    /// \brief The linker will always export this atom dynamically.
+    dynamicExportAlways,
+  };
+
+  // Attributes describe a code model used by the atom.
+  enum CodeModel {
+    codeNA,           // no specific code model
+    // MIPS code models
+    codeMipsPIC,      // PIC function in a PIC / non-PIC mixed file
+    codeMipsMicro,    // microMIPS instruction encoding
+    codeMipsMicroPIC, // microMIPS instruction encoding + PIC
+    codeMips16,       // MIPS-16 instruction encoding
+    // ARM code models
+    codeARMThumb,     // ARM Thumb instruction set
+    codeARM_a,        // $a-like mapping symbol (for ARM code)
+    codeARM_d,        // $d-like mapping symbol (for data)
+    codeARM_t,        // $t-like mapping symbol (for Thumb code)
+  };
+
+  struct Alignment {
+    Alignment(int v, int m = 0) : value(v), modulus(m) {}
+
+    uint16_t value;
+    uint16_t modulus;
+
+    bool operator==(const Alignment &rhs) const {
+      return (value == rhs.value) && (modulus == rhs.modulus);
+    }
+  };
+
+  /// \brief returns a value for the order of this Atom within its file.
+  ///
+  /// This is used by the linker to order the layout of Atoms so that the
+  /// resulting image is stable and reproducible.
+  virtual uint64_t ordinal() const = 0;
+
+  /// \brief the number of bytes of space this atom's content will occupy in the
+  /// final linked image.
+  ///
+  /// For a function atom, it is the number of bytes of code in the function.
+  virtual uint64_t size() const = 0;
+
+  /// \brief The size of the section from which the atom is instantiated.
+  ///
+  /// Merge::mergeByLargestSection is defined in terms of section size
+  /// and not in terms of atom size, so we need this function separate
+  /// from size().
+  virtual uint64_t sectionSize() const { return 0; }
+
+  /// \brief The visibility of this atom to other atoms.
+  ///
+  /// C static functions have scope scopeTranslationUnit.  Regular C functions
+  /// have scope scopeGlobal.  Functions compiled with visibility=hidden have
+  /// scope scopeLinkageUnit so they can be see by other atoms being linked but
+  /// not by the OS loader.
+  virtual Scope scope() const = 0;
+
+  /// \brief Whether the linker should use direct or indirect access to this
+  /// atom.
+  virtual Interposable interposable() const = 0;
+
+  /// \brief how the linker should handle if multiple atoms have the same name.
+  virtual Merge merge() const = 0;
+
+  /// \brief The type of this atom, such as code or data.
+  virtual ContentType contentType() const = 0;
+
+  /// \brief The alignment constraints on how this atom must be laid out in the
+  /// final linked image (e.g. 16-byte aligned).
+  virtual Alignment alignment() const = 0;
+
+  /// \brief Whether this atom must be in a specially named section in the final
+  /// linked image, or if the linker can infer the section based on the
+  /// contentType().
+  virtual SectionChoice sectionChoice() const = 0;
+
+  /// \brief If sectionChoice() != sectionBasedOnContent, then this return the
+  /// name of the section the atom should be placed into.
+  virtual StringRef customSectionName() const = 0;
+
+  /// \brief constraints on whether the linker may dead strip away this atom.
+  virtual DeadStripKind deadStrip() const = 0;
+
+  /// \brief Under which conditions should this atom be dynamically exported.
+  virtual DynamicExport dynamicExport() const {
+    return dynamicExportNormal;
+  }
+
+  /// \brief Code model used by the atom.
+  virtual CodeModel codeModel() const { return codeNA; }
+
+  /// \brief Returns the OS memory protections required for this atom's content
+  /// at runtime.
+  ///
+  /// A function atom is R_X, a global variable is RW_, and a read-only constant
+  /// is R__.
+  virtual ContentPermissions permissions() const;
+
+  /// \brief returns a reference to the raw (unrelocated) bytes of this Atom's
+  /// content.
+  virtual ArrayRef<uint8_t> rawContent() const = 0;
+
+  /// This class abstracts iterating over the sequence of References
+  /// in an Atom.  Concrete instances of DefinedAtom must implement
+  /// the derefIterator() and incrementIterator() methods.
+  class reference_iterator {
+  public:
+    reference_iterator(const DefinedAtom &a, const void *it)
+      : _atom(a), _it(it) { }
+
+    const Reference *operator*() const {
+      return _atom.derefIterator(_it);
+    }
+
+    const Reference *operator->() const {
+      return _atom.derefIterator(_it);
+    }
+
+    bool operator==(const reference_iterator &other) const {
+      return _it == other._it;
+    }
+
+    bool operator!=(const reference_iterator &other) const {
+      return !(*this == other);
+    }
+
+    reference_iterator &operator++() {
+      _atom.incrementIterator(_it);
+      return *this;
+    }
+  private:
+    const DefinedAtom &_atom;
+    const void *_it;
+  };
+
+  /// \brief Returns an iterator to the beginning of this Atom's References.
+  virtual reference_iterator begin() const = 0;
+
+  /// \brief Returns an iterator to the end of this Atom's References.
+  virtual reference_iterator end() const = 0;
+
+  /// Adds a reference to this atom.
+  virtual void addReference(Reference::KindNamespace ns,
+                            Reference::KindArch arch,
+                            Reference::KindValue kindValue, uint64_t off,
+                            const Atom *target, Reference::Addend a) {
+    llvm_unreachable("Subclass does not permit adding references");
+  }
+
+  static bool classof(const Atom *a) {
+    return a->definition() == definitionRegular;
+  }
+
+  /// Utility for deriving permissions from content type
+  static ContentPermissions permissions(ContentType type);
+
+  /// Utility function to check if the atom occupies file space
+  bool occupiesDiskSpace() const {
+    ContentType atomContentType = contentType();
+    return !(atomContentType == DefinedAtom::typeZeroFill ||
+             atomContentType == DefinedAtom::typeZeroFillFast ||
+             atomContentType == DefinedAtom::typeTLVInitialZeroFill);
+  }
+
+  /// Utility function to check if relocations in this atom to other defined
+  /// atoms can be implicitly generated, and so we don't need to explicitly
+  /// emit those relocations.
+  bool relocsToDefinedCanBeImplicit() const {
+    ContentType atomContentType = contentType();
+    return atomContentType == typeCFI;
+  }
+
+protected:
+  // DefinedAtom is an abstract base class. Only subclasses can access
+  // constructor.
+  DefinedAtom() : Atom(definitionRegular) { }
+
+  ~DefinedAtom() override = default;
+
+  /// \brief Returns a pointer to the Reference object that the abstract
+  /// iterator "points" to.
+  virtual const Reference *derefIterator(const void *iter) const = 0;
+
+  /// \brief Adjusts the abstract iterator to "point" to the next Reference
+  /// object for this Atom.
+  virtual void incrementIterator(const void *&iter) const = 0;
+};
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Error.h b/include/lld/Core/Error.h
new file mode 100644 (file)
index 0000000..b0bf73b
--- /dev/null
@@ -0,0 +1,68 @@
+//===- Error.h - system_error extensions for lld ----------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares a new error_category for the lld library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ERROR_H
+#define LLD_CORE_ERROR_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include <system_error>
+
+namespace lld {
+
+const std::error_category &YamlReaderCategory();
+
+enum class YamlReaderError {
+  unknown_keyword,
+  illegal_value
+};
+
+inline std::error_code make_error_code(YamlReaderError e) {
+  return std::error_code(static_cast<int>(e), YamlReaderCategory());
+}
+
+/// Creates an error_code object that has associated with it an arbitrary
+/// error messsage.  The value() of the error_code will always be non-zero
+/// but its value is meaningless. The messsage() will be (a copy of) the
+/// supplied error string.
+/// Note:  Once ErrorOr<> is updated to work with errors other than error_code,
+/// this can be updated to return some other kind of error.
+std::error_code make_dynamic_error_code(StringRef msg);
+
+/// Generic error.
+///
+/// For errors that don't require their own specific sub-error (most errors)
+/// this class can be used to describe the error via a string message.
+class GenericError : public llvm::ErrorInfo<GenericError> {
+public:
+  static char ID;
+  GenericError(Twine Msg);
+  const std::string &getMessage() const { return Msg; }
+  void log(llvm::raw_ostream &OS) const override;
+
+  std::error_code convertToErrorCode() const override {
+    return make_dynamic_error_code(getMessage());
+  }
+
+private:
+  std::string Msg;
+};
+
+} // end namespace lld
+
+namespace std {
+template <> struct is_error_code_enum<lld::YamlReaderError> : std::true_type {};
+}
+
+#endif
diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h
new file mode 100644 (file)
index 0000000..2041868
--- /dev/null
@@ -0,0 +1,278 @@
+//===- Core/File.h - A Container of Atoms ---------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_FILE_H
+#define LLD_CORE_FILE_H
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace lld {
+
+class LinkingContext;
+
+/// Every Atom is owned by some File. A common scenario is for a single
+/// object file (.o) to be parsed by some reader and produce a single
+/// File object that represents the content of that object file.
+///
+/// To iterate through the Atoms in a File there are four methods that
+/// return collections.  For instance to iterate through all the DefinedAtoms
+/// in a File object use:
+///      for (const DefinedAtoms *atom : file->defined()) {
+///      }
+///
+/// The Atom objects in a File are owned by the File object.  The Atom objects
+/// are destroyed when the File object is destroyed.
+class File {
+public:
+  virtual ~File();
+
+  /// \brief Kinds of files that are supported.
+  enum Kind {
+    kindErrorObject,          ///< a error object file (.o)
+    kindNormalizedObject,     ///< a normalized file (.o)
+    kindMachObject,           ///< a MachO object file (.o)
+    kindCEntryObject,         ///< a file for CEntries
+    kindHeaderObject,         ///< a file for file headers
+    kindEntryObject,          ///< a file for the entry
+    kindUndefinedSymsObject,  ///< a file for undefined symbols
+    kindStubHelperObject,     ///< a file for stub helpers
+    kindResolverMergedObject, ///< the resolver merged file.
+    kindSectCreateObject,     ///< a sect create object file (.o)
+    kindSharedLibrary,        ///< shared library (.so)
+    kindArchiveLibrary        ///< archive (.a)
+  };
+
+  /// \brief Returns file kind.  Need for dyn_cast<> on File objects.
+  Kind kind() const {
+    return _kind;
+  }
+
+  /// This returns the path to the file which was used to create this object
+  /// (e.g. "/tmp/foo.o"). If the file is a member of an archive file, the
+  /// returned string includes the archive file name.
+  StringRef path() const {
+    if (_archivePath.empty())
+      return _path;
+    if (_archiveMemberPath.empty())
+      _archiveMemberPath = (_archivePath + "(" + _path + ")").str();
+    return _archiveMemberPath;
+  }
+
+  /// Returns the path of the archive file name if this file is instantiated
+  /// from an archive file. Otherwise returns the empty string.
+  StringRef archivePath() const { return _archivePath; }
+  void setArchivePath(StringRef path) { _archivePath = path; }
+
+  /// Returns the path name of this file. It doesn't include archive file name.
+  StringRef memberPath() const { return _path; }
+
+  /// Returns the command line order of the file.
+  uint64_t ordinal() const {
+    assert(_ordinal != UINT64_MAX);
+    return _ordinal;
+  }
+
+  /// Returns true/false depending on whether an ordinal has been set.
+  bool hasOrdinal() const { return (_ordinal != UINT64_MAX); }
+
+  /// Sets the command line order of the file.
+  void setOrdinal(uint64_t ordinal) const { _ordinal = ordinal; }
+
+  /// Returns the ordinal for the next atom to be defined in this file.
+  uint64_t getNextAtomOrdinalAndIncrement() const {
+    return _nextAtomOrdinal++;
+  }
+
+  /// For allocating any objects owned by this File.
+  llvm::BumpPtrAllocator &allocator() const {
+    return _allocator;
+  }
+
+  /// The type of atom mutable container.
+  template <typename T> using AtomVector = std::vector<OwningAtomPtr<T>>;
+
+  /// The range type for the atoms.
+  template <typename T> class AtomRange {
+  public:
+    AtomRange(AtomVector<T> &v) : _v(v) {}
+    AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {}
+
+    typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&,
+                                           const T*> ConstDerefFn;
+
+    typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn;
+
+    typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
+                                  ConstDerefFn> ConstItTy;
+    typedef llvm::mapped_iterator<typename AtomVector<T>::iterator,
+                                  DerefFn> ItTy;
+
+    static const T* DerefConst(const OwningAtomPtr<T> &p) {
+      return p.get();
+    }
+
+    static T* Deref(OwningAtomPtr<T> &p) {
+      return p.get();
+    }
+
+    ConstItTy begin() const {
+      return ConstItTy(_v.begin(), ConstDerefFn(DerefConst));
+    }
+    ConstItTy end() const {
+      return ConstItTy(_v.end(), ConstDerefFn(DerefConst));
+    }
+
+    ItTy begin() {
+      return ItTy(_v.begin(), DerefFn(Deref));
+    }
+    ItTy end() {
+      return ItTy(_v.end(), DerefFn(Deref));
+    }
+
+    llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() {
+      return llvm::make_range(_v.begin(), _v.end());
+    }
+
+    llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() const {
+      return llvm::make_range(_v.begin(), _v.end());
+    }
+
+    bool empty() const {
+      return _v.empty();
+    }
+
+    size_t size() const {
+      return _v.size();
+    }
+
+    const OwningAtomPtr<T> &operator[](size_t idx) const {
+      return _v[idx];
+    }
+
+    OwningAtomPtr<T> &operator[](size_t idx) {
+      return _v[idx];
+    }
+
+  private:
+    AtomVector<T> &_v;
+  };
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all DefinedAtoms in this File.
+  virtual const AtomRange<DefinedAtom> defined() const = 0;
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all UndefinedAtomw in this File.
+  virtual const AtomRange<UndefinedAtom> undefined() const = 0;
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all SharedLibraryAtoms in this File.
+  virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0;
+
+  /// \brief Must be implemented to return the AtomVector object for
+  /// all AbsoluteAtoms in this File.
+  virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
+
+  /// Drop all of the atoms owned by this file.  This will result in all of
+  /// the atoms running their destructors.
+  /// This is required because atoms may be allocated on a BumpPtrAllocator
+  /// of a different file.  We need to destruct all atoms before any files.
+  virtual void clearAtoms() = 0;
+
+  /// \brief If a file is parsed using a different method than doParse(),
+  /// one must use this method to set the last error status, so that
+  /// doParse will not be called twice. Only YAML reader uses this
+  /// (because YAML reader does not read blobs but structured data).
+  void setLastError(std::error_code err) { _lastError = err; }
+
+  std::error_code parse();
+
+  // Usually each file owns a std::unique_ptr<MemoryBuffer>.
+  // However, there's one special case. If a file is an archive file,
+  // the archive file and its children all shares the same memory buffer.
+  // This method is used by the ArchiveFile to give its children
+  // co-ownership of the buffer.
+  void setSharedMemoryBuffer(std::shared_ptr<MemoryBuffer> mb) {
+    _sharedMemoryBuffer = mb;
+  }
+
+protected:
+  /// \brief only subclasses of File can be instantiated
+  File(StringRef p, Kind kind)
+    : _path(p), _kind(kind), _ordinal(UINT64_MAX),
+      _nextAtomOrdinal(0) {}
+
+  /// \brief Subclasses should override this method to parse the
+  /// memory buffer passed to this file's constructor.
+  virtual std::error_code doParse() { return std::error_code(); }
+
+  static AtomVector<DefinedAtom> _noDefinedAtoms;
+  static AtomVector<UndefinedAtom> _noUndefinedAtoms;
+  static AtomVector<SharedLibraryAtom> _noSharedLibraryAtoms;
+  static AtomVector<AbsoluteAtom> _noAbsoluteAtoms;
+  mutable llvm::BumpPtrAllocator _allocator;
+
+private:
+  StringRef _path;
+  std::string _archivePath;
+  mutable std::string _archiveMemberPath;
+  Kind              _kind;
+  mutable uint64_t  _ordinal;
+  mutable uint64_t _nextAtomOrdinal;
+  std::shared_ptr<MemoryBuffer> _sharedMemoryBuffer;
+  llvm::Optional<std::error_code> _lastError;
+  std::mutex _parseMutex;
+};
+
+/// An ErrorFile represents a file that doesn't exist.
+/// If you try to parse a file which doesn't exist, an instance of this
+/// class will be returned. That's parse method always returns an error.
+/// This is useful to delay erroring on non-existent files, so that we
+/// can do unit testing a driver using non-existing file paths.
+class ErrorFile : public File {
+public:
+  ErrorFile(StringRef path, std::error_code ec)
+      : File(path, kindErrorObject), _ec(ec) {}
+
+  std::error_code doParse() override { return _ec; }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    llvm_unreachable("internal error");
+  }
+  const AtomRange<UndefinedAtom> undefined() const override {
+    llvm_unreachable("internal error");
+  }
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    llvm_unreachable("internal error");
+  }
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    llvm_unreachable("internal error");
+  }
+
+  void clearAtoms() override {
+  }
+
+private:
+  std::error_code _ec;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Instrumentation.h b/include/lld/Core/Instrumentation.h
new file mode 100644 (file)
index 0000000..1623759
--- /dev/null
@@ -0,0 +1,132 @@
+//===- include/Core/Instrumentation.h - Instrumentation API ---------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provide an Instrumentation API that optionally uses VTune interfaces.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_INSTRUMENTATION_H
+#define LLD_CORE_INSTRUMENTATION_H
+
+#include "llvm/Support/Compiler.h"
+#include <utility>
+
+#ifdef LLD_HAS_VTUNE
+# include <ittnotify.h>
+#endif
+
+namespace lld {
+#ifdef LLD_HAS_VTUNE
+/// \brief A unique global scope for instrumentation data.
+///
+/// Domains last for the lifetime of the application and cannot be destroyed.
+/// Multiple Domains created with the same name represent the same domain.
+class Domain {
+  __itt_domain *_domain;
+
+public:
+  explicit Domain(const char *name) : _domain(__itt_domain_createA(name)) {}
+
+  operator __itt_domain *() const { return _domain; }
+  __itt_domain *operator->() const { return _domain; }
+};
+
+/// \brief A global reference to a string constant.
+///
+/// These are uniqued by the ITT runtime and cannot be deleted. They are not
+/// specific to a domain.
+///
+/// Prefer reusing a single StringHandle over passing a ntbs when the same
+/// string will be used often.
+class StringHandle {
+  __itt_string_handle *_handle;
+
+public:
+  StringHandle(const char *name) : _handle(__itt_string_handle_createA(name)) {}
+
+  operator __itt_string_handle *() const { return _handle; }
+};
+
+/// \brief A task on a single thread. Nests within other tasks.
+///
+/// Each thread has its own task stack and tasks nest recursively on that stack.
+/// A task cannot transfer threads.
+///
+/// SBRM is used to ensure task starts and ends are ballanced. The lifetime of
+/// a task is either the lifetime of this object, or until end is called.
+class ScopedTask {
+  __itt_domain *_domain;
+
+  ScopedTask(const ScopedTask &) = delete;
+  ScopedTask &operator=(const ScopedTask &) = delete;
+
+public:
+  /// \brief Create a task in Domain \p d named \p s.
+  ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) {
+    __itt_task_begin(d, __itt_null, __itt_null, s);
+  }
+
+  ScopedTask(ScopedTask &&other) {
+    *this = std::move(other);
+  }
+
+  ScopedTask &operator=(ScopedTask &&other) {
+    _domain = other._domain;
+    other._domain = nullptr;
+    return *this;
+  }
+
+  /// \brief Prematurely end this task.
+  void end() {
+    if (_domain)
+      __itt_task_end(_domain);
+    _domain = nullptr;
+  }
+
+  ~ScopedTask() { end(); }
+};
+
+/// \brief A specific point in time. Allows metadata to be associated.
+class Marker {
+public:
+  Marker(const Domain &d, const StringHandle &s) {
+    __itt_marker(d, __itt_null, s, __itt_scope_global);
+  }
+};
+#else
+class Domain {
+public:
+  Domain(const char *name) {}
+};
+
+class StringHandle {
+public:
+  StringHandle(const char *name) {}
+};
+
+class ScopedTask {
+public:
+  ScopedTask(const Domain &d, const StringHandle &s) {}
+  void end() {}
+};
+
+class Marker {
+public:
+  Marker(const Domain &d, const StringHandle &s) {}
+};
+#endif
+
+inline const Domain &getDefaultDomain() {
+  static Domain domain("org.llvm.lld");
+  return domain;
+}
+} // end namespace lld.
+
+#endif
diff --git a/include/lld/Core/LLVM.h b/include/lld/Core/LLVM.h
new file mode 100644 (file)
index 0000000..ccf0885
--- /dev/null
@@ -0,0 +1,83 @@
+//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file forward declares and imports various common LLVM datatypes that
+// lld wants to use unqualified.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_LLVM_H
+#define LLD_CORE_LLVM_H
+
+// This should be the only #include, force #includes of all the others on
+// clients.
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/Casting.h"
+#include <utility>
+
+namespace llvm {
+  // ADT's.
+  class Error;
+  class StringRef;
+  class Twine;
+  class MemoryBuffer;
+  class MemoryBufferRef;
+  template<typename T> class ArrayRef;
+  template<unsigned InternalLen> class SmallString;
+  template<typename T, unsigned N> class SmallVector;
+  template<typename T> class SmallVectorImpl;
+
+  template<typename T>
+  struct SaveAndRestore;
+
+  template<typename T>
+  class ErrorOr;
+
+  template<typename T>
+  class Expected;
+
+  class raw_ostream;
+  // TODO: DenseMap, ...
+}
+
+namespace lld {
+  // Casting operators.
+  using llvm::isa;
+  using llvm::cast;
+  using llvm::dyn_cast;
+  using llvm::dyn_cast_or_null;
+  using llvm::cast_or_null;
+
+  // ADT's.
+  using llvm::Error;
+  using llvm::StringRef;
+  using llvm::Twine;
+  using llvm::MemoryBuffer;
+  using llvm::MemoryBufferRef;
+  using llvm::ArrayRef;
+  using llvm::SmallString;
+  using llvm::SmallVector;
+  using llvm::SmallVectorImpl;
+  using llvm::SaveAndRestore;
+  using llvm::ErrorOr;
+  using llvm::Expected;
+
+  using llvm::raw_ostream;
+} // end namespace lld.
+
+namespace std {
+template <> struct hash<llvm::StringRef> {
+public:
+  size_t operator()(const llvm::StringRef &s) const {
+    return llvm::hash_value(s);
+  }
+};
+}
+
+#endif
diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h
new file mode 100644 (file)
index 0000000..b3a999b
--- /dev/null
@@ -0,0 +1,258 @@
+//===- lld/Core/LinkingContext.h - Linker Target Info Interface -*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_LINKING_CONTEXT_H
+#define LLD_CORE_LINKING_CONTEXT_H
+
+#include "lld/Core/Node.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace lld {
+
+class PassManager;
+class File;
+class Writer;
+class Node;
+class SharedLibraryFile;
+
+/// \brief The LinkingContext class encapsulates "what and how" to link.
+///
+/// The base class LinkingContext contains the options needed by core linking.
+/// Subclasses of LinkingContext have additional options needed by specific
+/// Writers.
+class LinkingContext {
+public:
+  virtual ~LinkingContext();
+
+  /// \name Methods needed by core linking
+  /// @{
+
+  /// Name of symbol linker should use as "entry point" to program,
+  /// usually "main" or "start".
+  virtual StringRef entrySymbolName() const { return _entrySymbolName; }
+
+  /// Whether core linking should remove Atoms not reachable by following
+  /// References from the entry point Atom or from all global scope Atoms
+  /// if globalsAreDeadStripRoots() is true.
+  bool deadStrip() const { return _deadStrip; }
+
+  /// Only used if deadStrip() returns true.  Means all global scope Atoms
+  /// should be marked live (along with all Atoms they reference).  Usually
+  /// this method returns false for main executables, but true for dynamic
+  /// shared libraries.
+  bool globalsAreDeadStripRoots() const { return _globalsAreDeadStripRoots; }
+
+  /// Only used if deadStrip() returns true.  This method returns the names
+  /// of DefinedAtoms that should be marked live (along with all Atoms they
+  /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can
+  /// be kept live using this method.
+  const std::vector<StringRef> &deadStripRoots() const {
+    return _deadStripRoots;
+  }
+
+  /// Add the given symbol name to the dead strip root set. Only used if
+  /// deadStrip() returns true.
+  void addDeadStripRoot(StringRef symbolName) {
+    assert(!symbolName.empty() && "Empty symbol cannot be a dead strip root");
+    _deadStripRoots.push_back(symbolName);
+  }
+
+  /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+  /// SharedLibraryAtom for the link to be successful.  This method controls
+  /// whether core linking prints out a list of remaining UndefinedAtoms.
+  ///
+  /// \todo This should be a method core linking calls with a list of the
+  /// UndefinedAtoms so that different drivers can format the error message
+  /// as needed.
+  bool printRemainingUndefines() const { return _printRemainingUndefines; }
+
+  /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+  /// SharedLibraryAtom for the link to be successful.  This method controls
+  /// whether core linking considers remaining undefines to be an error.
+  bool allowRemainingUndefines() const { return _allowRemainingUndefines; }
+
+  /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+  /// SharedLibraryAtom for the link to be successful.  This method controls
+  /// whether core linking considers remaining undefines from the shared library
+  /// to be an error.
+  bool allowShlibUndefines() const { return _allowShlibUndefines; }
+
+  /// If true, core linking will write the path to each input file to stdout
+  /// (i.e. llvm::outs()) as it is used.  This is used to implement the -t
+  /// linker option.
+  ///
+  /// \todo This should be a method core linking calls so that drivers can
+  /// format the line as needed.
+  bool logInputFiles() const { return _logInputFiles; }
+
+  /// Parts of LLVM use global variables which are bound to command line
+  /// options (see llvm::cl::Options). This method returns "command line"
+  /// options which are used to configure LLVM's command line settings.
+  /// For instance the -debug-only XXX option can be used to dynamically
+  /// trace different parts of LLVM and lld.
+  const std::vector<const char *> &llvmOptions() const { return _llvmOptions; }
+
+  /// \name Methods used by Drivers to configure TargetInfo
+  /// @{
+  void setOutputPath(StringRef str) { _outputPath = str; }
+
+  // Set the entry symbol name. You may also need to call addDeadStripRoot() for
+  // the symbol if your platform supports dead-stripping, so that the symbol
+  // will not be removed from the output.
+  void setEntrySymbolName(StringRef name) {
+    _entrySymbolName = name;
+  }
+
+  void setDeadStripping(bool enable) { _deadStrip = enable; }
+  void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
+
+  void setPrintRemainingUndefines(bool print) {
+    _printRemainingUndefines = print;
+  }
+
+  void setAllowRemainingUndefines(bool allow) {
+    _allowRemainingUndefines = allow;
+  }
+
+  void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; }
+  void setLogInputFiles(bool log) { _logInputFiles = log; }
+
+  void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); }
+
+  std::vector<std::unique_ptr<Node>> &getNodes() { return _nodes; }
+  const std::vector<std::unique_ptr<Node>> &getNodes() const { return _nodes; }
+
+  /// This method adds undefined symbols specified by the -u option to the to
+  /// the list of undefined symbols known to the linker. This option essentially
+  /// forces an undefined symbol to be created. You may also need to call
+  /// addDeadStripRoot() for the symbol if your platform supports dead
+  /// stripping, so that the symbol will not be removed from the output.
+  void addInitialUndefinedSymbol(StringRef symbolName) {
+    _initialUndefinedSymbols.push_back(symbolName);
+  }
+
+  /// Iterators for symbols that appear on the command line.
+  typedef std::vector<StringRef> StringRefVector;
+  typedef StringRefVector::iterator StringRefVectorIter;
+  typedef StringRefVector::const_iterator StringRefVectorConstIter;
+
+  /// Create linker internal files containing atoms for the linker to include
+  /// during link. Flavors can override this function in their LinkingContext
+  /// to add more internal files. These internal files are positioned before
+  /// the actual input files.
+  virtual void createInternalFiles(std::vector<std::unique_ptr<File>> &) const;
+
+  /// Return the list of undefined symbols that are specified in the
+  /// linker command line, using the -u option.
+  ArrayRef<StringRef> initialUndefinedSymbols() const {
+    return _initialUndefinedSymbols;
+  }
+
+  /// After all set* methods are called, the Driver calls this method
+  /// to validate that there are no missing options or invalid combinations
+  /// of options.  If there is a problem, a description of the problem
+  /// is written to the supplied stream.
+  ///
+  /// \returns true if there is an error with the current settings.
+  bool validate(raw_ostream &diagnostics);
+
+  /// Formats symbol name for use in error messages.
+  virtual std::string demangle(StringRef symbolName) const = 0;
+
+  /// @}
+  /// \name Methods used by Driver::link()
+  /// @{
+
+  /// Returns the file system path to which the linked output should be written.
+  ///
+  /// \todo To support in-memory linking, we need an abstraction that allows
+  /// the linker to write to an in-memory buffer.
+  StringRef outputPath() const { return _outputPath; }
+
+  /// Accessor for Register object embedded in LinkingContext.
+  const Registry &registry() const { return _registry; }
+  Registry &registry() { return _registry; }
+
+  /// This method is called by core linking to give the Writer a chance
+  /// to add file format specific "files" to set of files to be linked. This is
+  /// how file format specific atoms can be added to the link.
+  virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) = 0;
+
+  /// This method is called by core linking to build the list of Passes to be
+  /// run on the merged/linked graph of all input files.
+  virtual void addPasses(PassManager &pm) = 0;
+
+  /// Calls through to the writeFile() method on the specified Writer.
+  ///
+  /// \param linkedFile This is the merged/linked graph of all input file Atoms.
+  virtual llvm::Error writeFile(const File &linkedFile) const;
+
+  /// Return the next ordinal and Increment it.
+  virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; }
+
+  // This function is called just before the Resolver kicks in.
+  // Derived classes may use it to change the list of input files.
+  virtual void finalizeInputFiles() = 0;
+
+  /// Callback invoked for each file the Resolver decides we are going to load.
+  /// This can be used to update context state based on the file, and emit
+  /// errors for any differences between the context state and a loaded file.
+  /// For example, we can error if we try to load a file which is a different
+  /// arch from that being linked.
+  virtual llvm::Error handleLoadedFile(File &file) = 0;
+
+  /// @}
+protected:
+  LinkingContext(); // Must be subclassed
+
+  /// Abstract method to lazily instantiate the Writer.
+  virtual Writer &writer() const = 0;
+
+  /// Method to create an internal file for the entry symbol
+  virtual std::unique_ptr<File> createEntrySymbolFile() const;
+  std::unique_ptr<File> createEntrySymbolFile(StringRef filename) const;
+
+  /// Method to create an internal file for an undefined symbol
+  virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
+  std::unique_ptr<File> createUndefinedSymbolFile(StringRef filename) const;
+
+  StringRef _outputPath;
+  StringRef _entrySymbolName;
+  bool _deadStrip = false;
+  bool _globalsAreDeadStripRoots = false;
+  bool _printRemainingUndefines = true;
+  bool _allowRemainingUndefines = false;
+  bool _logInputFiles = false;
+  bool _allowShlibUndefines = false;
+  std::vector<StringRef> _deadStripRoots;
+  std::vector<const char *> _llvmOptions;
+  StringRefVector _initialUndefinedSymbols;
+  std::vector<std::unique_ptr<Node>> _nodes;
+  mutable llvm::BumpPtrAllocator _allocator;
+  mutable uint64_t _nextOrdinal = 0;
+  Registry _registry;
+
+private:
+  /// Validate the subclass bits. Only called by validate.
+  virtual bool validateImpl(raw_ostream &diagnostics) = 0;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_LINKING_CONTEXT_H
diff --git a/include/lld/Core/Node.h b/include/lld/Core/Node.h
new file mode 100644 (file)
index 0000000..c304824
--- /dev/null
@@ -0,0 +1,75 @@
+//===- lld/Core/Node.h - Input file class -----------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// The classes in this file represents inputs to the linker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_NODE_H
+#define LLD_CORE_NODE_H
+
+#include "lld/Core/File.h"
+#include <algorithm>
+#include <memory>
+
+namespace lld {
+
+// A Node represents a FileNode or other type of Node. In the latter case,
+// the node contains meta information about the input file list.
+// Currently only GroupEnd node is defined as a meta node.
+class Node {
+public:
+  enum class Kind { File, GroupEnd };
+
+  explicit Node(Kind type) : _kind(type) {}
+  virtual ~Node() = default;
+
+  virtual Kind kind() const { return _kind; }
+
+private:
+  Kind _kind;
+};
+
+// This is a marker for --end-group. getSize() returns the number of
+// files between the corresponding --start-group and this marker.
+class GroupEnd : public Node {
+public:
+  explicit GroupEnd(int size) : Node(Kind::GroupEnd), _size(size) {}
+
+  int getSize() const { return _size; }
+
+  static bool classof(const Node *a) {
+    return a->kind() == Kind::GroupEnd;
+  }
+
+private:
+  int _size;
+};
+
+// A container of File.
+class FileNode : public Node {
+public:
+  explicit FileNode(std::unique_ptr<File> f)
+      : Node(Node::Kind::File), _file(std::move(f)) {}
+
+  static bool classof(const Node *a) {
+    return a->kind() == Node::Kind::File;
+  }
+
+  File *getFile() { return _file.get(); }
+
+protected:
+  std::unique_ptr<File> _file;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_NODE_H
diff --git a/include/lld/Core/Pass.h b/include/lld/Core/Pass.h
new file mode 100644 (file)
index 0000000..bfe3f9b
--- /dev/null
@@ -0,0 +1,43 @@
+//===------ Core/Pass.h - Base class for linker passes ----------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_PASS_H
+#define LLD_CORE_PASS_H
+
+#include "llvm/Support/Error.h"
+
+namespace lld {
+
+class SimpleFile;
+
+/// Once the core linking is done (which resolves references, coalesces atoms
+/// and produces a complete Atom graph), the linker runs a series of passes
+/// on the Atom graph. The graph is modeled as a File, which means the pass
+/// has access to all the atoms and to File level attributes. Each pass does
+/// a particular transformation to the Atom graph or to the File attributes.
+///
+/// This is the abstract base class for all passes.  A Pass does its
+/// actual work in it perform() method.  It can iterator over Atoms in the
+/// graph using the *begin()/*end() atom iterator of the File.  It can add
+/// new Atoms to the graph using the File's addAtom() method.
+class Pass {
+public:
+  virtual ~Pass() = default;
+
+  /// Do the actual work of the Pass.
+  virtual llvm::Error perform(SimpleFile &mergedFile) = 0;
+
+protected:
+  // Only subclassess can be instantiated.
+  Pass() = default;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_PASS_H
diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h
new file mode 100644 (file)
index 0000000..09b417a
--- /dev/null
@@ -0,0 +1,48 @@
+//===- lld/Core/PassManager.h - Manage linker passes ----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_PASS_MANAGER_H
+#define LLD_CORE_PASS_MANAGER_H
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Pass.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+class SimpleFile;
+class Pass;
+
+/// \brief Owns and runs a collection of passes.
+///
+/// This class is currently just a container for passes and a way to run them.
+///
+/// In the future this should handle timing pass runs, running parallel passes,
+/// and validate/satisfy pass dependencies.
+class PassManager {
+public:
+  void add(std::unique_ptr<Pass> pass) {
+    _passes.push_back(std::move(pass));
+  }
+
+  llvm::Error runOnFile(SimpleFile &file) {
+    for (std::unique_ptr<Pass> &pass : _passes)
+      if (llvm::Error EC = pass->perform(file))
+        return EC;
+    return llvm::Error::success();
+  }
+
+private:
+  /// \brief Passes in the order they should run.
+  std::vector<std::unique_ptr<Pass>> _passes;
+};
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h
new file mode 100644 (file)
index 0000000..32d0424
--- /dev/null
@@ -0,0 +1,155 @@
+//===- lld/Core/Reader.h - Abstract File Format Reading Interface ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_READER_H
+#define LLD_CORE_READER_H
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace yaml {
+class IO;
+} // end namespace yaml
+} // end namespace llvm
+
+namespace lld {
+
+class File;
+class LinkingContext;
+class MachOLinkingContext;
+
+/// \brief An abstract class for reading object files, library files, and
+/// executable files.
+///
+/// Each file format (e.g. mach-o, etc) has a concrete subclass of Reader.
+class Reader {
+public:
+  virtual ~Reader() = default;
+
+  /// Sniffs the file to determine if this Reader can parse it.
+  /// The method is called with:
+  /// 1) the file_magic enumeration returned by identify_magic()
+  /// 2) the whole file content buffer if the above is not enough.
+  virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0;
+
+  /// \brief Parse a supplied buffer (already filled with the contents of a
+  /// file) and create a File object.
+  /// The resulting File object takes ownership of the MemoryBuffer.
+  virtual ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &) const = 0;
+};
+
+/// \brief An abstract class for handling alternate yaml representations
+/// of object files.
+///
+/// The YAML syntax allows "tags" which are used to specify the type of
+/// the YAML node.  In lld, top level YAML documents can be in many YAML
+/// representations (e.g mach-o encoded as yaml, etc).  A tag is used to
+/// specify which representation is used in the following YAML document.
+/// To work, there must be a YamlIOTaggedDocumentHandler registered that
+/// handles each tag type.
+class YamlIOTaggedDocumentHandler {
+public:
+  virtual ~YamlIOTaggedDocumentHandler();
+
+  /// This method is called on each registered YamlIOTaggedDocumentHandler
+  /// until one returns true.  If the subclass handles tag type !xyz, then
+  /// this method should call io.mapTag("!xzy") to see if that is the current
+  /// document type, and if so, process the rest of the document using
+  /// YAML I/O, then convert the result into an lld::File* and return it.
+  virtual bool handledDocTag(llvm::yaml::IO &io, const lld::File *&f) const = 0;
+};
+
+/// A registry to hold the list of currently registered Readers and
+/// tables which map Reference kind values to strings.
+/// The linker does not directly invoke Readers.  Instead, it registers
+/// Readers based on it configuration and command line options, then calls
+/// the Registry object to parse files.
+class Registry {
+public:
+  Registry();
+
+  /// Walk the list of registered Readers and find one that can parse the
+  /// supplied file and parse it.
+  ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb) const;
+
+  /// Walk the list of registered kind tables to convert a Reference Kind
+  /// name to a value.
+  bool referenceKindFromString(StringRef inputStr, Reference::KindNamespace &ns,
+                               Reference::KindArch &a,
+                               Reference::KindValue &value) const;
+
+  /// Walk the list of registered kind tables to convert a Reference Kind
+  /// value to a string.
+  bool referenceKindToString(Reference::KindNamespace ns, Reference::KindArch a,
+                             Reference::KindValue value, StringRef &) const;
+
+  /// Walk the list of registered tag handlers and have the one that handles
+  /// the current document type process the yaml into an lld::File*.
+  bool handleTaggedDoc(llvm::yaml::IO &io, const lld::File *&file) const;
+
+  // These methods are called to dynamically add support for various file
+  // formats. The methods are also implemented in the appropriate lib*.a
+  // library, so that the code for handling a format is only linked in, if this
+  // method is used.  Any options that a Reader might need must be passed
+  // as parameters to the addSupport*() method.
+  void addSupportArchives(bool logLoading);
+  void addSupportYamlFiles();
+  void addSupportMachOObjects(MachOLinkingContext &);
+
+  /// To convert between kind values and names, the registry walks the list
+  /// of registered kind tables. Each table is a zero terminated array of
+  /// KindStrings elements.
+  struct KindStrings {
+    Reference::KindValue  value;
+    StringRef             name;
+  };
+
+  /// A Reference Kind value is a tuple of <namespace, arch, value>.  All
+  /// entries in a conversion table have the same <namespace, arch>.  The
+  /// array then contains the value/name pairs.
+  void addKindTable(Reference::KindNamespace ns, Reference::KindArch arch,
+                    const KindStrings array[]);
+
+private:
+  struct KindEntry {
+    Reference::KindNamespace  ns;
+    Reference::KindArch       arch;
+    const KindStrings        *array;
+  };
+
+  void add(std::unique_ptr<Reader>);
+  void add(std::unique_ptr<YamlIOTaggedDocumentHandler>);
+
+  std::vector<std::unique_ptr<Reader>>                       _readers;
+  std::vector<std::unique_ptr<YamlIOTaggedDocumentHandler>>  _yamlHandlers;
+  std::vector<KindEntry>                                     _kindEntries;
+};
+
+// Utilities for building a KindString table.  For instance:
+//   static const Registry::KindStrings table[] = {
+//      LLD_KIND_STRING_ENTRY(R_VAX_ADDR16),
+//      LLD_KIND_STRING_ENTRY(R_VAX_DATA16),
+//      LLD_KIND_STRING_END
+//   };
+#define LLD_KIND_STRING_ENTRY(name) { name, #name }
+#define LLD_KIND_STRING_END         { 0,    "" }
+
+} // end namespace lld
+
+#endif // LLD_CORE_READER_H
diff --git a/include/lld/Core/Reference.h b/include/lld/Core/Reference.h
new file mode 100644 (file)
index 0000000..1d3003c
--- /dev/null
@@ -0,0 +1,119 @@
+//===- Core/References.h - A Reference to Another Atom ----------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_REFERENCES_H
+#define LLD_CORE_REFERENCES_H
+
+#include <cstdint>
+
+namespace lld {
+
+class Atom;
+
+///
+/// The linker has a Graph Theory model of linking. An object file is seen
+/// as a set of Atoms with References to other Atoms.  Each Atom is a node
+/// and each Reference is an edge.
+///
+/// For example if a function contains a call site to "malloc" 40 bytes into
+/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40,
+/// kind=callsite, target=malloc, addend=0.
+///
+/// Besides supporting traditional "relocations", references are also used
+/// forcing layout (one atom must follow another), marking data-in-code
+/// (jump tables or ARM constants), etc.
+///
+/// The "kind" of a reference is a tuple of <namespace, arch, value>.  This
+/// enable us to re-use existing relocation types definded for various
+/// file formats and architectures.
+///
+/// References and atoms form a directed graph. The dead-stripping pass
+/// traverses them starting from dead-strip root atoms to garbage collect
+/// unreachable ones.
+///
+/// References of any kind are considered as directed edges. In addition to
+/// that, references of some kind is considered as bidirected edges.
+class Reference {
+public:
+  /// Which universe defines the kindValue().
+  enum class KindNamespace {
+    all     = 0,
+    testing = 1,
+    mach_o  = 2,
+  };
+
+  KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; }
+  void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; }
+
+  // Which architecture the kind value is for.
+  enum class KindArch { all, AArch64, ARM, x86, x86_64};
+
+  KindArch kindArch() const { return (KindArch)_kindArch; }
+  void setKindArch(KindArch a) { _kindArch = (uint8_t)a; }
+
+  typedef uint16_t KindValue;
+
+  KindValue kindValue() const { return _kindValue; }
+
+  /// setKindValue() is needed because during linking, some optimizations may
+  /// change the codegen and hence the reference kind.
+  void setKindValue(KindValue value) {
+    _kindValue = value;
+  }
+
+  /// KindValues used with KindNamespace::all and KindArch::all.
+  enum {
+    // kindLayoutAfter is treated as a bidirected edge by the dead-stripping
+    // pass.
+    kindLayoutAfter = 1,
+    kindAssociate,
+  };
+
+  // A value to be added to the value of a target
+  typedef int64_t Addend;
+
+  /// If the reference is a fixup in the Atom, then this returns the
+  /// byte offset into the Atom's content to do the fix up.
+  virtual uint64_t offsetInAtom() const = 0;
+
+  /// Returns the atom this reference refers to.
+  virtual const Atom *target() const = 0;
+
+  /// During linking, the linker may merge graphs which coalesces some nodes
+  /// (i.e. Atoms).  To switch the target of a reference, this method is called.
+  virtual void setTarget(const Atom *) = 0;
+
+  /// Some relocations require a symbol and a value (e.g. foo + 4).
+  virtual Addend addend() const = 0;
+
+  /// During linking, some optimzations may change addend value.
+  virtual void setAddend(Addend) = 0;
+
+  /// Returns target specific attributes of the reference.
+  virtual uint32_t tag() const { return 0; }
+
+protected:
+  /// Reference is an abstract base class.  Only subclasses can use constructor.
+  Reference(KindNamespace ns, KindArch a, KindValue value)
+      : _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {}
+
+  /// The memory for Reference objects is always managed by the owning File
+  /// object.  Therefore, no one but the owning File object should call
+  /// delete on an Reference.  In fact, some File objects may bulk allocate
+  /// an array of References, so they cannot be individually deleted by anyone.
+  virtual ~Reference() = default;
+
+  KindValue  _kindValue;
+  uint8_t    _kindNamespace;
+  uint8_t    _kindArch;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_REFERENCES_H
diff --git a/include/lld/Core/Reproduce.h b/include/lld/Core/Reproduce.h
new file mode 100644 (file)
index 0000000..6e1d36a
--- /dev/null
@@ -0,0 +1,39 @@
+//===- Reproduce.h - Utilities for creating reproducers ---------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_REPRODUCE_H
+#define LLD_CORE_REPRODUCE_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace opt { class Arg; }
+}
+
+namespace lld {
+
+// Makes a given pathname an absolute path first, and then remove
+// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
+// assuming that the current directory is "/home/john/bar".
+std::string relativeToRoot(StringRef Path);
+
+// Quote a given string if it contains a space character.
+std::string quote(StringRef S);
+
+// Rewrite the given path if a file exists with that pathname, otherwise
+// returns the original path.
+std::string rewritePath(StringRef S);
+
+// Returns the string form of the given argument.
+std::string toString(llvm::opt::Arg *Arg);
+}
+
+#endif
diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h
new file mode 100644 (file)
index 0000000..fb62a77
--- /dev/null
@@ -0,0 +1,106 @@
+//===- Core/Resolver.h - Resolves Atom References -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_RESOLVER_H
+#define LLD_CORE_RESOLVER_H
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/SymbolTable.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/ErrorOr.h"
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace lld {
+
+class Atom;
+class LinkingContext;
+
+/// \brief The Resolver is responsible for merging all input object files
+/// and producing a merged graph.
+class Resolver {
+public:
+  Resolver(LinkingContext &ctx) : _ctx(ctx), _result(new MergedFile()) {}
+
+  // InputFiles::Handler methods
+  void doDefinedAtom(OwningAtomPtr<DefinedAtom> atom);
+  bool doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom);
+  void doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom);
+  void doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom);
+
+  // Handle files, this adds atoms from the current file thats
+  // being processed by the resolver
+  llvm::Expected<bool> handleFile(File &);
+
+  // Handle an archive library file.
+  llvm::Expected<bool> handleArchiveFile(File &);
+
+  // Handle a shared library file.
+  llvm::Error handleSharedLibrary(File &);
+
+  /// @brief do work of merging and resolving and return list
+  bool resolve();
+
+  std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); }
+
+private:
+  typedef std::function<llvm::Expected<bool>(StringRef)> UndefCallback;
+
+  bool undefinesAdded(int begin, int end);
+  File *getFile(int &index);
+
+  /// \brief The main function that iterates over the files to resolve
+  bool resolveUndefines();
+  void updateReferences();
+  void deadStripOptimize();
+  bool checkUndefines();
+  void removeCoalescedAwayAtoms();
+  llvm::Expected<bool> forEachUndefines(File &file, UndefCallback callback);
+
+  void markLive(const Atom *atom);
+
+  class MergedFile : public SimpleFile {
+  public:
+    MergedFile() : SimpleFile("<linker-internal>", kindResolverMergedObject) {}
+    void addAtoms(llvm::MutableArrayRef<OwningAtomPtr<Atom>> atoms);
+  };
+
+  LinkingContext &_ctx;
+  SymbolTable _symbolTable;
+  std::vector<OwningAtomPtr<Atom>>     _atoms;
+  std::set<const Atom *>        _deadStripRoots;
+  llvm::DenseSet<const Atom *>  _liveAtoms;
+  llvm::DenseSet<const Atom *>  _deadAtoms;
+  std::unique_ptr<MergedFile>   _result;
+  std::unordered_multimap<const Atom *, const Atom *> _reverseRef;
+
+  // --start-group and --end-group
+  std::vector<File *> _files;
+  std::map<File *, bool> _newUndefinesAdded;
+
+  // List of undefined symbols.
+  std::vector<StringRef> _undefines;
+
+  // Start position in _undefines for each archive/shared library file.
+  // Symbols from index 0 to the start position are already searched before.
+  // Searching them again would never succeed. When we look for undefined
+  // symbols from an archive/shared library file, start from its start
+  // position to save time.
+  std::map<File *, size_t> _undefineIndex;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_RESOLVER_H
diff --git a/include/lld/Core/SharedLibraryAtom.h b/include/lld/Core/SharedLibraryAtom.h
new file mode 100644 (file)
index 0000000..7fec7a3
--- /dev/null
@@ -0,0 +1,53 @@
+//===- Core/SharedLibraryAtom.h - A Shared Library Atom -------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SHARED_LIBRARY_ATOM_H
+#define LLD_CORE_SHARED_LIBRARY_ATOM_H
+
+#include "lld/Core/Atom.h"
+
+namespace lld {
+
+/// A SharedLibraryAtom has no content.
+/// It exists to represent a symbol which will be bound at runtime.
+class SharedLibraryAtom : public Atom {
+public:
+  enum class Type : uint32_t {
+    Unknown,
+    Code,
+    Data,
+  };
+
+  /// Returns shared library name used to load it at runtime.
+  /// On Darwin it is the LC_DYLIB_LOAD dylib name.
+  virtual StringRef loadName() const = 0;
+
+  /// Returns if shared library symbol can be missing at runtime and if
+  /// so the loader should silently resolve address of symbol to be nullptr.
+  virtual bool canBeNullAtRuntime() const = 0;
+
+  virtual Type type() const = 0;
+
+  virtual uint64_t size() const = 0;
+
+  static bool classof(const Atom *a) {
+    return a->definition() == definitionSharedLibrary;
+  }
+
+  static inline bool classof(const SharedLibraryAtom *) { return true; }
+
+protected:
+  SharedLibraryAtom() : Atom(definitionSharedLibrary) {}
+
+  ~SharedLibraryAtom() override = default;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H
diff --git a/include/lld/Core/SharedLibraryFile.h b/include/lld/Core/SharedLibraryFile.h
new file mode 100644 (file)
index 0000000..53bf967
--- /dev/null
@@ -0,0 +1,70 @@
+//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H
+#define LLD_CORE_SHARED_LIBRARY_FILE_H
+
+#include "lld/Core/File.h"
+
+namespace lld {
+
+///
+/// The SharedLibraryFile subclass of File is used to represent dynamic
+/// shared libraries being linked against.
+///
+class SharedLibraryFile : public File {
+public:
+  static bool classof(const File *f) {
+    return f->kind() == kindSharedLibrary;
+  }
+
+  /// Check if the shared library exports a symbol with the specified name.
+  /// If so, return a SharedLibraryAtom which represents that exported
+  /// symbol.  Otherwise return nullptr.
+  virtual OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const = 0;
+
+  // Returns the install name.
+  virtual StringRef getDSOName() const = 0;
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _definedAtoms;
+  }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _undefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _sharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _absoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _definedAtoms.clear();
+    _undefinedAtoms.clear();
+    _sharedLibraryAtoms.clear();
+    _absoluteAtoms.clear();
+  }
+
+protected:
+  /// only subclasses of SharedLibraryFile can be instantiated
+  explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {}
+
+  AtomVector<DefinedAtom> _definedAtoms;
+  AtomVector<UndefinedAtom> _undefinedAtoms;
+  AtomVector<SharedLibraryAtom> _sharedLibraryAtoms;
+  AtomVector<AbsoluteAtom> _absoluteAtoms;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SHARED_LIBRARY_FILE_H
diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h
new file mode 100644 (file)
index 0000000..3aa7abf
--- /dev/null
@@ -0,0 +1,271 @@
+//===- lld/Core/Simple.h - Simple implementations of Atom and File --------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provide simple implementations for Atoms and File.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SIMPLE_H
+#define LLD_CORE_SIMPLE_H
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <functional>
+
+namespace lld {
+
+class SimpleFile : public File {
+public:
+  SimpleFile(StringRef path, File::Kind kind)
+    : File(path, kind) {}
+
+  ~SimpleFile() override {
+    _defined.clear();
+    _undefined.clear();
+    _shared.clear();
+    _absolute.clear();
+  }
+
+  void addAtom(DefinedAtom &a) {
+    _defined.push_back(OwningAtomPtr<DefinedAtom>(&a));
+  }
+  void addAtom(UndefinedAtom &a) {
+    _undefined.push_back(OwningAtomPtr<UndefinedAtom>(&a));
+  }
+  void addAtom(SharedLibraryAtom &a) {
+    _shared.push_back(OwningAtomPtr<SharedLibraryAtom>(&a));
+  }
+  void addAtom(AbsoluteAtom &a) {
+    _absolute.push_back(OwningAtomPtr<AbsoluteAtom>(&a));
+  }
+
+  void addAtom(const Atom &atom) {
+    if (auto *p = dyn_cast<DefinedAtom>(&atom)) {
+      addAtom(const_cast<DefinedAtom &>(*p));
+    } else if (auto *p = dyn_cast<UndefinedAtom>(&atom)) {
+      addAtom(const_cast<UndefinedAtom &>(*p));
+    } else if (auto *p = dyn_cast<SharedLibraryAtom>(&atom)) {
+      addAtom(const_cast<SharedLibraryAtom &>(*p));
+    } else if (auto *p = dyn_cast<AbsoluteAtom>(&atom)) {
+      addAtom(const_cast<AbsoluteAtom &>(*p));
+    } else {
+      llvm_unreachable("atom has unknown definition kind");
+    }
+  }
+
+  void removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) {
+    auto &atoms = _defined;
+    auto newEnd = std::remove_if(atoms.begin(), atoms.end(),
+                                 [&pred](OwningAtomPtr<DefinedAtom> &p) {
+                                   return pred(p.get());
+                                 });
+    atoms.erase(newEnd, atoms.end());
+  }
+
+  const AtomRange<DefinedAtom> defined() const override { return _defined; }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _undefined;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _shared;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _absolute;
+  }
+
+  void clearAtoms() override {
+    _defined.clear();
+    _undefined.clear();
+    _shared.clear();
+    _absolute.clear();
+  }
+
+private:
+  AtomVector<DefinedAtom> _defined;
+  AtomVector<UndefinedAtom> _undefined;
+  AtomVector<SharedLibraryAtom> _shared;
+  AtomVector<AbsoluteAtom> _absolute;
+};
+
+class SimpleReference : public Reference,
+                        public llvm::ilist_node<SimpleReference> {
+public:
+  SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch,
+                  Reference::KindValue value, uint64_t off, const Atom *t,
+                  Reference::Addend a)
+      : Reference(ns, arch, value), _target(t), _offsetInAtom(off), _addend(a) {
+  }
+  SimpleReference()
+      : Reference(Reference::KindNamespace::all, Reference::KindArch::all, 0),
+        _target(nullptr), _offsetInAtom(0), _addend(0) {}
+
+  uint64_t offsetInAtom() const override { return _offsetInAtom; }
+
+  const Atom *target() const override {
+    assert(_target);
+    return _target;
+  }
+
+  Addend addend() const override { return _addend; }
+  void setAddend(Addend a) override { _addend = a; }
+  void setTarget(const Atom *newAtom) override { _target = newAtom; }
+
+private:
+  const Atom *_target;
+  uint64_t _offsetInAtom;
+  Addend _addend;
+};
+
+class SimpleDefinedAtom : public DefinedAtom {
+public:
+  explicit SimpleDefinedAtom(const File &f)
+      : _file(f), _ordinal(f.getNextAtomOrdinalAndIncrement()) {}
+
+  ~SimpleDefinedAtom() override {
+    _references.clearAndLeakNodesUnsafely();
+  }
+
+  const File &file() const override { return _file; }
+
+  StringRef name() const override { return StringRef(); }
+
+  uint64_t ordinal() const override { return _ordinal; }
+
+  Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+  Interposable interposable() const override {
+    return DefinedAtom::interposeNo;
+  }
+
+  Merge merge() const override { return DefinedAtom::mergeNo; }
+
+  Alignment alignment() const override { return 1; }
+
+  SectionChoice sectionChoice() const override {
+    return DefinedAtom::sectionBasedOnContent;
+  }
+
+  StringRef customSectionName() const override { return StringRef(); }
+  DeadStripKind deadStrip() const override {
+    return DefinedAtom::deadStripNormal;
+  }
+
+  DefinedAtom::reference_iterator begin() const override {
+    const void *it =
+        reinterpret_cast<const void *>(_references.begin().getNodePtr());
+    return reference_iterator(*this, it);
+  }
+
+  DefinedAtom::reference_iterator end() const override {
+    const void *it =
+        reinterpret_cast<const void *>(_references.end().getNodePtr());
+    return reference_iterator(*this, it);
+  }
+
+  const Reference *derefIterator(const void *it) const override {
+    return &*RefList::const_iterator(
+        *reinterpret_cast<const llvm::ilist_node<SimpleReference> *>(it));
+  }
+
+  void incrementIterator(const void *&it) const override {
+    RefList::const_iterator ref(
+        *reinterpret_cast<const llvm::ilist_node<SimpleReference> *>(it));
+    it = reinterpret_cast<const void *>(std::next(ref).getNodePtr());
+  }
+
+  void addReference(Reference::KindNamespace ns,
+                    Reference::KindArch arch,
+                    Reference::KindValue kindValue, uint64_t off,
+                    const Atom *target, Reference::Addend a) override {
+    assert(target && "trying to create reference to nothing");
+    auto node = new (_file.allocator())
+        SimpleReference(ns, arch, kindValue, off, target, a);
+    _references.push_back(node);
+  }
+
+  /// Sort references in a canonical order (by offset, then by kind).
+  void sortReferences() const {
+    // Cannot sort a linked  list, so move elements into a temporary vector,
+    // sort the vector, then reconstruct the list.
+    llvm::SmallVector<SimpleReference *, 16> elements;
+    for (SimpleReference &node : _references) {
+      elements.push_back(&node);
+    }
+    std::sort(elements.begin(), elements.end(),
+        [] (const SimpleReference *lhs, const SimpleReference *rhs) -> bool {
+          uint64_t lhsOffset = lhs->offsetInAtom();
+          uint64_t rhsOffset = rhs->offsetInAtom();
+          if (rhsOffset != lhsOffset)
+            return (lhsOffset < rhsOffset);
+          if (rhs->kindNamespace() != lhs->kindNamespace())
+            return (lhs->kindNamespace() < rhs->kindNamespace());
+          if (rhs->kindArch() != lhs->kindArch())
+            return (lhs->kindArch() < rhs->kindArch());
+          return (lhs->kindValue() < rhs->kindValue());
+        });
+    _references.clearAndLeakNodesUnsafely();
+    for (SimpleReference *node : elements) {
+      _references.push_back(node);
+    }
+  }
+
+  void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+private:
+  typedef llvm::ilist<SimpleReference> RefList;
+
+  const File &_file;
+  uint64_t _ordinal;
+  mutable RefList _references;
+};
+
+class SimpleUndefinedAtom : public UndefinedAtom {
+public:
+  SimpleUndefinedAtom(const File &f, StringRef name) : _file(f), _name(name) {
+    assert(!name.empty() && "UndefinedAtoms must have a name");
+  }
+
+  ~SimpleUndefinedAtom() override = default;
+
+  /// file - returns the File that produced/owns this Atom
+  const File &file() const override { return _file; }
+
+  /// name - The name of the atom. For a function atom, it is the (mangled)
+  /// name of the function.
+  StringRef name() const override { return _name; }
+
+  CanBeNull canBeNull() const override { return UndefinedAtom::canBeNullNever; }
+
+private:
+  const File &_file;
+  StringRef _name;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_SIMPLE_H
diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h
new file mode 100644 (file)
index 0000000..ba4951e
--- /dev/null
@@ -0,0 +1,96 @@
+//===- Core/SymbolTable.h - Main Symbol Table -----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SYMBOL_TABLE_H
+#define LLD_CORE_SYMBOL_TABLE_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include <cstring>
+#include <map>
+#include <vector>
+
+namespace lld {
+
+class AbsoluteAtom;
+class Atom;
+class DefinedAtom;
+class LinkingContext;
+class ResolverOptions;
+class SharedLibraryAtom;
+class UndefinedAtom;
+
+/// \brief The SymbolTable class is responsible for coalescing atoms.
+///
+/// All atoms coalescable by-name or by-content should be added.
+/// The method replacement() can be used to find the replacement atom
+/// if an atom has been coalesced away.
+class SymbolTable {
+public:
+  /// @brief add atom to symbol table
+  bool add(const DefinedAtom &);
+
+  /// @brief add atom to symbol table
+  bool add(const UndefinedAtom &);
+
+  /// @brief add atom to symbol table
+  bool add(const SharedLibraryAtom &);
+
+  /// @brief add atom to symbol table
+  bool add(const AbsoluteAtom &);
+
+  /// @brief returns atom in symbol table for specified name (or nullptr)
+  const Atom *findByName(StringRef sym);
+
+  /// @brief returns vector of remaining UndefinedAtoms
+  std::vector<const UndefinedAtom *> undefines();
+
+  /// @brief if atom has been coalesced away, return replacement, else return atom
+  const Atom *replacement(const Atom *);
+
+  /// @brief if atom has been coalesced away, return true
+  bool isCoalescedAway(const Atom *);
+
+private:
+  typedef llvm::DenseMap<const Atom *, const Atom *> AtomToAtom;
+
+  struct StringRefMappingInfo {
+    static StringRef getEmptyKey() { return StringRef(); }
+    static StringRef getTombstoneKey() { return StringRef(" ", 1); }
+    static unsigned getHashValue(StringRef const val) {
+      return llvm::HashString(val);
+    }
+    static bool isEqual(StringRef const lhs, StringRef const rhs) {
+      return lhs.equals(rhs);
+    }
+  };
+  typedef llvm::DenseMap<StringRef, const Atom *,
+                                           StringRefMappingInfo> NameToAtom;
+
+  struct AtomMappingInfo {
+    static const DefinedAtom * getEmptyKey() { return nullptr; }
+    static const DefinedAtom * getTombstoneKey() { return (DefinedAtom*)(-1); }
+    static unsigned getHashValue(const DefinedAtom * const Val);
+    static bool isEqual(const DefinedAtom * const LHS,
+                        const DefinedAtom * const RHS);
+  };
+  typedef llvm::DenseSet<const DefinedAtom*, AtomMappingInfo> AtomContentSet;
+
+  bool addByName(const Atom &);
+  bool addByContent(const DefinedAtom &);
+
+  AtomToAtom _replacedAtoms;
+  NameToAtom _nameTable;
+  AtomContentSet _contentTable;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SYMBOL_TABLE_H
diff --git a/include/lld/Core/TODO.txt b/include/lld/Core/TODO.txt
new file mode 100644 (file)
index 0000000..8b52304
--- /dev/null
@@ -0,0 +1,17 @@
+include/lld/Core
+~~~~~~~~~~~~~~~~
+
+* The yaml reader/writer interfaces should be changed to return
+  an explanatory string if there is an error.  The existing error_code
+  abstraction only works for returning low level OS errors.  It does not
+  work for describing formatting issues.
+
+* We need to design a diagnostics interface.  It would be nice to share code
+  with Clang_ where possible.
+
+* We need to add more attributes to File.  In particular, we need cpu
+  and OS information (like target triples).  We should also provide explicit
+  support for `LLVM IR module flags metadata`__.
+
+.. __: http://llvm.org/docs/LangRef.html#module_flags
+.. _Clang: http://clang.llvm.org/docs/InternalsManual.html#Diagnostics
diff --git a/include/lld/Core/TargetOptionsCommandFlags.h b/include/lld/Core/TargetOptionsCommandFlags.h
new file mode 100644 (file)
index 0000000..9ba99d9
--- /dev/null
@@ -0,0 +1,20 @@
+//===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper to create TargetOptions from command line flags.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Target/TargetOptions.h"
+
+namespace lld {
+llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
+llvm::CodeModel::Model GetCodeModelFromCMModel();
+}
diff --git a/include/lld/Core/UndefinedAtom.h b/include/lld/Core/UndefinedAtom.h
new file mode 100644 (file)
index 0000000..f45d6ec
--- /dev/null
@@ -0,0 +1,68 @@
+//===- Core/UndefinedAtom.h - An Undefined Atom ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_UNDEFINED_ATOM_H
+#define LLD_CORE_UNDEFINED_ATOM_H
+
+#include "lld/Core/Atom.h"
+
+namespace lld {
+
+/// An UndefinedAtom has no content.
+/// It exists as a placeholder for a future atom.
+class UndefinedAtom : public Atom {
+public:
+  /// Whether this undefined symbol needs to be resolved,
+  /// or whether it can just evaluate to nullptr.
+  /// This concept is often called "weak", but that term
+  /// is overloaded to mean other things too.
+  enum CanBeNull {
+    /// Normal symbols must be resolved at build time
+    canBeNullNever,
+
+    /// This symbol can be missing at runtime and will evalute to nullptr.
+    /// That is, the static linker still must find a definition (usually
+    /// is some shared library), but at runtime, the dynamic loader
+    /// will allow the symbol to be missing and resolved to nullptr.
+    ///
+    /// On Darwin this is generated using a function prototype with
+    /// __attribute__((weak_import)).
+    /// On linux this is generated using a function prototype with
+    ///  __attribute__((weak)).
+    /// On Windows this feature is not supported.
+    canBeNullAtRuntime,
+
+    /// This symbol can be missing at build time.
+    /// That is, the static linker will not error if a definition for
+    /// this symbol is not found at build time. Instead, the linker
+    /// will build an executable that lets the dynamic loader find the
+    /// symbol at runtime.
+    /// This feature is not supported on Darwin nor Windows.
+    /// On linux this is generated using a function prototype with
+    ///  __attribute__((weak)).
+    canBeNullAtBuildtime
+  };
+
+  virtual CanBeNull canBeNull() const = 0;
+
+  static bool classof(const Atom *a) {
+    return a->definition() == definitionUndefined;
+  }
+
+  static bool classof(const UndefinedAtom *) { return true; }
+
+protected:
+  UndefinedAtom() : Atom(definitionUndefined) {}
+
+  ~UndefinedAtom() override = default;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_UNDEFINED_ATOM_H
diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h
new file mode 100644 (file)
index 0000000..216f934
--- /dev/null
@@ -0,0 +1,47 @@
+//===- lld/Core/Writer.h - Abstract File Format Interface -----------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_WRITER_H
+#define LLD_CORE_WRITER_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+class File;
+class LinkingContext;
+class MachOLinkingContext;
+
+/// \brief The Writer is an abstract class for writing object files, shared
+/// library files, and executable files.  Each file format (e.g. mach-o, etc)
+/// has a concrete subclass of Writer.
+class Writer {
+public:
+  virtual ~Writer();
+
+  /// \brief Write a file from the supplied File object
+  virtual llvm::Error writeFile(const File &linkedFile, StringRef path) = 0;
+
+  /// \brief This method is called by Core Linking to give the Writer a chance
+  /// to add file format specific "files" to set of files to be linked. This is
+  /// how file format specific atoms can be added to the link.
+  virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) {}
+
+protected:
+  // only concrete subclasses can be instantiated
+  Writer();
+};
+
+std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &);
+std::unique_ptr<Writer> createWriterYAML(const LinkingContext &);
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Driver/Driver.h b/include/lld/Driver/Driver.h
new file mode 100644 (file)
index 0000000..4ba0994
--- /dev/null
@@ -0,0 +1,33 @@
+//===- lld/Driver/Driver.h - Linker Driver Emulator -----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DRIVER_DRIVER_H
+#define LLD_DRIVER_DRIVER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace coff {
+bool link(llvm::ArrayRef<const char *> Args,
+          llvm::raw_ostream &Diag = llvm::errs());
+}
+
+namespace elf {
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
+          llvm::raw_ostream &Diag = llvm::errs());
+}
+
+namespace mach_o {
+bool link(llvm::ArrayRef<const char *> Args,
+          llvm::raw_ostream &Diag = llvm::errs());
+}
+}
+
+#endif
diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h
new file mode 100644 (file)
index 0000000..9eefa8c
--- /dev/null
@@ -0,0 +1,508 @@
+//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
+
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <set>
+
+using llvm::MachO::HeaderFileType;
+
+namespace lld {
+
+namespace mach_o {
+class ArchHandler;
+class MachODylibFile;
+class MachOFile;
+class SectCreateFile;
+}
+
+class MachOLinkingContext : public LinkingContext {
+public:
+  MachOLinkingContext();
+  ~MachOLinkingContext() override;
+
+  enum Arch {
+    arch_unknown,
+    arch_ppc,
+    arch_x86,
+    arch_x86_64,
+    arch_armv6,
+    arch_armv7,
+    arch_armv7s,
+    arch_arm64,
+  };
+
+  enum class OS {
+    unknown,
+    macOSX,
+    iOS,
+    iOS_simulator
+  };
+
+  enum class ExportMode {
+    globals,    // Default, all global symbols exported.
+    whiteList,  // -exported_symbol[s_list], only listed symbols exported.
+    blackList   // -unexported_symbol[s_list], no listed symbol exported.
+  };
+
+  enum class DebugInfoMode {
+    addDebugMap,    // Default
+    noDebugMap      // -S option
+  };
+
+  enum class UndefinedMode {
+    error,
+    warning,
+    suppress,
+    dynamicLookup
+  };
+
+  enum ObjCConstraint {
+    objc_unknown = 0,
+    objc_supports_gc = 2,
+    objc_gc_only = 4,
+    // Image optimized by dyld = 8
+    // GC compaction = 16
+    objc_retainReleaseForSimulator = 32,
+    objc_retainRelease
+  };
+
+  /// Initializes the context to sane default values given the specified output
+  /// file type, arch, os, and minimum os version.  This should be called before
+  /// other setXXX() methods.
+  void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion,
+                 bool exportDynamicSymbols);
+
+  void addPasses(PassManager &pm) override;
+  bool validateImpl(raw_ostream &diagnostics) override;
+  std::string demangle(StringRef symbolName) const override;
+
+  void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+  /// Creates a new file which is owned by the context.  Returns a pointer to
+  /// the new file.
+  template <class T, class... Args>
+  typename std::enable_if<!std::is_array<T>::value, T *>::type
+  make_file(Args &&... args) const {
+    auto file = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+    auto *filePtr = file.get();
+    auto *ctx = const_cast<MachOLinkingContext *>(this);
+    ctx->getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+    return filePtr;
+  }
+
+  uint32_t getCPUType() const;
+  uint32_t getCPUSubType() const;
+
+  bool addEntryPointLoadCommand() const;
+  bool addUnixThreadLoadCommand() const;
+  bool outputTypeHasEntry() const;
+  bool is64Bit() const;
+
+  virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
+  virtual uint64_t pageSize() const { return _pageSize; }
+
+  mach_o::ArchHandler &archHandler() const;
+
+  HeaderFileType outputMachOType() const { return _outputMachOType; }
+
+  Arch arch() const { return _arch; }
+  StringRef archName() const { return nameFromArch(_arch); }
+  OS os() const { return _os; }
+
+  ExportMode exportMode() const { return _exportMode; }
+  void setExportMode(ExportMode mode) { _exportMode = mode; }
+  void addExportSymbol(StringRef sym);
+  bool exportRestrictMode() const { return _exportMode != ExportMode::globals; }
+  bool exportSymbolNamed(StringRef sym) const;
+
+  DebugInfoMode debugInfoMode() const { return _debugInfoMode; }
+  void setDebugInfoMode(DebugInfoMode mode) {
+    _debugInfoMode = mode;
+  }
+
+  void appendOrderedSymbol(StringRef symbol, StringRef filename);
+
+  bool keepPrivateExterns() const { return _keepPrivateExterns; }
+  void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; }
+  bool demangleSymbols() const { return _demangle; }
+  void setDemangleSymbols(bool d) { _demangle = d; }
+  bool mergeObjCCategories() const { return _mergeObjCCategories; }
+  void setMergeObjCCategories(bool v) { _mergeObjCCategories = v; }
+  /// Create file at specified path which will contain a binary encoding
+  /// of all input and output file paths.
+  std::error_code createDependencyFile(StringRef path);
+  void addInputFileDependency(StringRef path) const;
+  void addInputFileNotFound(StringRef path) const;
+  void addOutputFileDependency(StringRef path) const;
+
+  bool minOS(StringRef mac, StringRef iOS) const;
+  void setDoNothing(bool value) { _doNothing = value; }
+  bool doNothing() const { return _doNothing; }
+  bool printAtoms() const { return _printAtoms; }
+  bool testingFileUsage() const { return _testingFileUsage; }
+  const StringRefVector &searchDirs() const { return _searchDirs; }
+  const StringRefVector &frameworkDirs() const { return _frameworkDirs; }
+  void setSysLibRoots(const StringRefVector &paths);
+  const StringRefVector &sysLibRoots() const { return _syslibRoots; }
+  bool PIE() const { return _pie; }
+  void setPIE(bool pie) { _pie = pie; }
+  bool generateVersionLoadCommand() const {
+    return _generateVersionLoadCommand;
+  }
+  void setGenerateVersionLoadCommand(bool v) {
+    _generateVersionLoadCommand = v;
+  }
+
+  bool generateFunctionStartsLoadCommand() const {
+    return _generateFunctionStartsLoadCommand;
+  }
+  void setGenerateFunctionStartsLoadCommand(bool v) {
+    _generateFunctionStartsLoadCommand = v;
+  }
+
+  bool generateDataInCodeLoadCommand() const {
+    return _generateDataInCodeLoadCommand;
+  }
+  void setGenerateDataInCodeLoadCommand(bool v) {
+    _generateDataInCodeLoadCommand = v;
+  }
+
+  uint64_t stackSize() const { return _stackSize; }
+  void setStackSize(uint64_t stackSize) { _stackSize = stackSize; }
+
+  uint64_t baseAddress() const { return _baseAddress; }
+  void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; }
+
+  ObjCConstraint objcConstraint() const { return _objcConstraint; }
+
+  uint32_t osMinVersion() const { return _osMinVersion; }
+
+  uint32_t sdkVersion() const { return _sdkVersion; }
+  void setSdkVersion(uint64_t v) { _sdkVersion = v; }
+
+  uint64_t sourceVersion() const { return _sourceVersion; }
+  void setSourceVersion(uint64_t v) { _sourceVersion = v; }
+
+  uint32_t swiftVersion() const { return _swiftVersion; }
+
+  /// \brief Checks whether a given path on the filesystem exists.
+  ///
+  /// When running in -test_file_usage mode, this method consults an
+  /// internally maintained list of files that exist (provided by -path_exists)
+  /// instead of the actual filesystem.
+  bool pathExists(StringRef path) const;
+
+  /// Like pathExists() but only used on files - not directories.
+  bool fileExists(StringRef path) const;
+
+  /// \brief Adds any library search paths derived from the given base, possibly
+  /// modified by -syslibroots.
+  ///
+  /// The set of paths added consists of approximately all syslibroot-prepended
+  /// versions of libPath that exist, or the original libPath if there are none
+  /// for whatever reason. With various edge-cases for compatibility.
+  void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false);
+
+  /// \brief Determine whether -lFoo can be resolve within the given path, and
+  /// return the filename if so.
+  ///
+  /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in
+  /// that order, unless Foo ends in ".o", in which case only the exact file
+  /// matches (e.g. -lfoo.o would only find foo.o).
+  llvm::Optional<StringRef> searchDirForLibrary(StringRef path,
+                                                StringRef libName) const;
+
+  /// \brief Iterates through all search path entries looking for libName (as
+  /// specified by -lFoo).
+  llvm::Optional<StringRef> searchLibrary(StringRef libName) const;
+
+  /// Add a framework search path.  Internally, this method may be prepended
+  /// the path with syslibroot.
+  void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
+
+  /// \brief Iterates through all framework directories looking for
+  /// Foo.framework/Foo (when fwName = "Foo").
+  llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const;
+
+  /// \brief The dylib's binary compatibility version, in the raw uint32 format.
+  ///
+  /// When building a dynamic library, this is the compatibility version that
+  /// gets embedded into the result. Other Mach-O binaries that link against
+  /// this library will store the compatibility version in its load command. At
+  /// runtime, the loader will verify that the binary is compatible with the
+  /// installed dynamic library.
+  uint32_t compatibilityVersion() const { return _compatibilityVersion; }
+
+  /// \brief The dylib's current version, in the the raw uint32 format.
+  ///
+  /// When building a dynamic library, this is the current version that gets
+  /// embedded into the result. Other Mach-O binaries that link against
+  /// this library will store the compatibility version in its load command.
+  uint32_t currentVersion() const { return _currentVersion; }
+
+  /// \brief The dylib's install name.
+  ///
+  /// Binaries that link against the dylib will embed this path into the dylib
+  /// load command. When loading the binaries at runtime, this is the location
+  /// on disk that the loader will look for the dylib.
+  StringRef installName() const { return _installName; }
+
+  /// \brief Whether or not the dylib has side effects during initialization.
+  ///
+  /// Dylibs marked as being dead strippable provide the guarantee that loading
+  /// the dylib has no side effects, allowing the linker to strip out the dylib
+  /// when linking a binary that does not use any of its symbols.
+  bool deadStrippableDylib() const { return _deadStrippableDylib; }
+
+  /// \brief Whether or not to use flat namespace.
+  ///
+  /// MachO usually uses a two-level namespace, where each external symbol
+  /// referenced by the target is associated with the dylib that will provide
+  /// the symbol's definition at runtime. Using flat namespace overrides this
+  /// behavior: the linker searches all dylibs on the command line and all
+  /// dylibs those original dylibs depend on, but does not record which dylib
+  /// an external symbol came from. At runtime dyld again searches all images
+  /// and uses the first definition it finds. In addition, any undefines in
+  /// loaded flat_namespace dylibs must be resolvable at build time.
+  bool useFlatNamespace() const { return _flatNamespace; }
+
+  /// \brief How to handle undefined symbols.
+  ///
+  /// Options are:
+  ///  * error: Report an error and terminate linking.
+  ///  * warning: Report a warning, but continue linking.
+  ///  * suppress: Ignore and continue linking.
+  ///  * dynamic_lookup: For use with -twolevel namespace: Records source dylibs
+  ///    for symbols that are defined in a linked dylib at static link time.
+  ///    Undefined symbols are handled by searching all loaded images at
+  ///    runtime.
+  UndefinedMode undefinedMode() const { return _undefinedMode; }
+
+  /// \brief The path to the executable that will load the bundle at runtime.
+  ///
+  /// When building a Mach-O bundle, this executable will be examined if there
+  /// are undefined symbols after the main link phase. It is expected that this
+  /// binary will be loading the bundle at runtime and will provide the symbols
+  /// at that point.
+  StringRef bundleLoader() const { return _bundleLoader; }
+
+  void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; }
+  void setCurrentVersion(uint32_t vers) { _currentVersion = vers; }
+  void setInstallName(StringRef name) { _installName = name; }
+  void setDeadStrippableDylib(bool deadStrippable) {
+    _deadStrippableDylib = deadStrippable;
+  }
+  void setUseFlatNamespace(bool flatNamespace) {
+    _flatNamespace = flatNamespace;
+  }
+
+  void setUndefinedMode(UndefinedMode undefinedMode) {
+    _undefinedMode = undefinedMode;
+  }
+
+  void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
+  void setPrintAtoms(bool value=true) { _printAtoms = value; }
+  void setTestingFileUsage(bool value = true) {
+    _testingFileUsage = value;
+  }
+  void addExistingPathForDebug(StringRef path) {
+    _existingPaths.insert(path);
+  }
+
+  void addRpath(StringRef rpath);
+  const StringRefVector &rpaths() const { return _rpaths; }
+
+  /// Add section alignment constraint on final layout.
+  void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align);
+
+  /// \brief Add a section based on a command-line sectcreate option.
+  void addSectCreateSection(StringRef seg, StringRef sect,
+                            std::unique_ptr<MemoryBuffer> content);
+
+  /// Returns true if specified section had alignment constraints.
+  bool sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const;
+
+  StringRef dyldPath() const { return "/usr/lib/dyld"; }
+
+  /// Stub creation Pass should be run.
+  bool needsStubsPass() const;
+
+  // GOT creation Pass should be run.
+  bool needsGOTPass() const;
+
+  /// Pass to add TLV sections.
+  bool needsTLVPass() const;
+
+  /// Pass to transform __compact_unwind into __unwind_info should be run.
+  bool needsCompactUnwindPass() const;
+
+  /// Pass to add shims switching between thumb and arm mode.
+  bool needsShimPass() const;
+
+  /// Pass to add objc image info and optimized objc data.
+  bool needsObjCPass() const;
+
+  /// Magic symbol name stubs will need to help lazy bind.
+  StringRef binderSymbolName() const;
+
+  /// Used to keep track of direct and indirect dylibs.
+  void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const;
+
+  // Reads a file from disk to memory. Returns only a needed chunk
+  // if a fat binary.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> getMemoryBuffer(StringRef path);
+
+  /// Used to find indirect dylibs. Instantiates a MachODylibFile if one
+  /// has not already been made for the requested dylib.  Uses -L and -F
+  /// search paths to allow indirect dylibs to be overridden.
+  mach_o::MachODylibFile* findIndirectDylib(StringRef path);
+
+  uint32_t dylibCurrentVersion(StringRef installName) const;
+
+  uint32_t dylibCompatVersion(StringRef installName) const;
+
+  ArrayRef<mach_o::MachODylibFile*> allDylibs() const {
+    return _allDylibs;
+  }
+
+  /// Creates a copy (owned by this MachOLinkingContext) of a string.
+  StringRef copy(StringRef str) { return str.copy(_allocator); }
+
+  /// If the memoryBuffer is a fat file with a slice for the current arch,
+  /// this method will return the offset and size of that slice.
+  bool sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, uint32_t &size);
+
+  /// Returns if a command line option specified dylib is an upward link.
+  bool isUpwardDylib(StringRef installName) const;
+
+  static bool isThinObjectFile(StringRef path, Arch &arch);
+  static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
+  static Arch archFromName(StringRef archName);
+  static StringRef nameFromArch(Arch arch);
+  static uint32_t cpuTypeFromArch(Arch arch);
+  static uint32_t cpuSubtypeFromArch(Arch arch);
+  static bool is64Bit(Arch arch);
+  static bool isHostEndian(Arch arch);
+  static bool isBigEndian(Arch arch);
+
+  /// Construct 32-bit value from string "X.Y.Z" where
+  /// bits are xxxx.yy.zz.  Largest number is 65535.255.255
+  static bool parsePackedVersion(StringRef str, uint32_t &result);
+
+  /// Construct 64-bit value from string "A.B.C.D.E" where
+  /// bits are aaaa.bb.cc.dd.ee.  Largest number is 16777215.1023.1023.1023.1023
+  static bool parsePackedVersion(StringRef str, uint64_t &result);
+
+  void finalizeInputFiles() override;
+
+  llvm::Error handleLoadedFile(File &file) override;
+
+  bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
+                         bool &leftBeforeRight) const;
+
+  /// Return the 'flat namespace' file. This is the file that supplies
+  /// atoms for otherwise undefined symbols when the -flat_namespace or
+  /// -undefined dynamic_lookup options are used.
+  File* flatNamespaceFile() const { return _flatNamespaceFile; }
+
+private:
+  Writer &writer() const override;
+  mach_o::MachODylibFile* loadIndirectDylib(StringRef path);
+  void checkExportWhiteList(const DefinedAtom *atom) const;
+  void checkExportBlackList(const DefinedAtom *atom) const;
+  struct ArchInfo {
+    StringRef                 archName;
+    MachOLinkingContext::Arch arch;
+    bool                      littleEndian;
+    uint32_t                  cputype;
+    uint32_t                  cpusubtype;
+  };
+
+  struct SectionAlign {
+    StringRef segmentName;
+    StringRef sectionName;
+    uint16_t  align;
+  };
+
+  struct OrderFileNode {
+    StringRef fileFilter;
+    unsigned  order;
+  };
+
+  static bool findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+                             const DefinedAtom *atom, unsigned &ordinal);
+
+  static ArchInfo _s_archInfos[];
+
+  std::set<StringRef> _existingPaths; // For testing only.
+  StringRefVector _searchDirs;
+  StringRefVector _syslibRoots;
+  StringRefVector _frameworkDirs;
+  HeaderFileType _outputMachOType = llvm::MachO::MH_EXECUTE;
+  bool _outputMachOTypeStatic = false; // Disambiguate static vs dynamic prog
+  bool _doNothing = false;             // for -help and -v which just print info
+  bool _pie = false;
+  Arch _arch = arch_unknown;
+  OS _os = OS::macOSX;
+  uint32_t _osMinVersion = 0;
+  uint32_t _sdkVersion = 0;
+  uint64_t _sourceVersion = 0;
+  uint64_t _pageZeroSize = 0;
+  uint64_t _pageSize = 4096;
+  uint64_t _baseAddress = 0;
+  uint64_t _stackSize = 0;
+  uint32_t _compatibilityVersion = 0;
+  uint32_t _currentVersion = 0;
+  ObjCConstraint _objcConstraint = objc_unknown;
+  uint32_t _swiftVersion = 0;
+  StringRef _installName;
+  StringRefVector _rpaths;
+  bool _flatNamespace = false;
+  UndefinedMode _undefinedMode = UndefinedMode::error;
+  bool _deadStrippableDylib = false;
+  bool _printAtoms = false;
+  bool _testingFileUsage = false;
+  bool _keepPrivateExterns = false;
+  bool _demangle = false;
+  bool _mergeObjCCategories = true;
+  bool _generateVersionLoadCommand = false;
+  bool _generateFunctionStartsLoadCommand = false;
+  bool _generateDataInCodeLoadCommand = false;
+  StringRef _bundleLoader;
+  mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
+  mutable std::unique_ptr<Writer> _writer;
+  std::vector<SectionAlign> _sectAligns;
+  mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
+  mutable std::vector<mach_o::MachODylibFile*> _allDylibs;
+  mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
+  mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
+  mutable std::mutex _dylibsMutex;
+  ExportMode _exportMode = ExportMode::globals;
+  llvm::StringSet<> _exportedSymbols;
+  DebugInfoMode _debugInfoMode = DebugInfoMode::addDebugMap;
+  std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo;
+  llvm::StringMap<std::vector<OrderFileNode>> _orderFiles;
+  unsigned _orderFileEntries = 0;
+  File *_flatNamespaceFile = nullptr;
+  mach_o::SectCreateFile *_sectCreateFile = nullptr;
+};
+
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
diff --git a/include/lld/ReaderWriter/YamlContext.h b/include/lld/ReaderWriter/YamlContext.h
new file mode 100644 (file)
index 0000000..b26161a
--- /dev/null
@@ -0,0 +1,42 @@
+//===- lld/ReaderWriter/YamlContext.h - object used in YAML I/O context ---===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_YAML_CONTEXT_H
+#define LLD_READER_WRITER_YAML_CONTEXT_H
+
+#include "lld/Core/LLVM.h"
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace lld {
+class File;
+class LinkingContext;
+namespace mach_o {
+namespace normalized {
+struct NormalizedFile;
+}
+}
+
+using lld::mach_o::normalized::NormalizedFile;
+
+/// When YAML I/O is used in lld, the yaml context always holds a YamlContext
+/// object.  We need to support hetergenous yaml documents which each require
+/// different context info.  This struct supports all clients.
+struct YamlContext {
+  const LinkingContext *_ctx = nullptr;
+  const Registry *_registry = nullptr;
+  File *_file = nullptr;
+  NormalizedFile *_normalizeMachOFile = nullptr;
+  StringRef _path;
+};
+
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_YAML_CONTEXT_H
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..699f5e9
--- /dev/null
@@ -0,0 +1,4 @@
+add_subdirectory(Config)
+add_subdirectory(Core)
+add_subdirectory(Driver)
+add_subdirectory(ReaderWriter)
diff --git a/lib/Config/CMakeLists.txt b/lib/Config/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3e142b6
--- /dev/null
@@ -0,0 +1,9 @@
+add_lld_library(lldConfig
+  Version.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLD_INCLUDE_DIR}/lld/Config
+
+  LINK_COMPONENTS
+    Support
+  )
diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp
new file mode 100644 (file)
index 0000000..2554475
--- /dev/null
@@ -0,0 +1,43 @@
+//===- lib/Config/Version.cpp - LLD Version Number ---------------*- C++-=====//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines several version-related utility functions for LLD.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Config/Version.h"
+
+using namespace llvm;
+
+// Returns an SVN repository path, which is usually "trunk".
+static std::string getRepositoryPath() {
+  StringRef S = LLD_REPOSITORY_STRING;
+  size_t Pos = S.find("lld/");
+  if (Pos != StringRef::npos)
+    return S.substr(Pos + 4);
+  return S;
+}
+
+// Returns an SVN repository name, e.g., " (trunk 284614)"
+// or an empty string if no repository info is available.
+static std::string getRepository() {
+  std::string Repo = getRepositoryPath();
+  std::string Rev = LLD_REVISION_STRING;
+
+  if (Repo.empty() && Rev.empty())
+    return "";
+  if (!Repo.empty() && !Rev.empty())
+    return " (" + Repo + " " + Rev + ")";
+  return " (" + Repo + Rev + ")";
+}
+
+// Returns a version string, e.g., "LLD 4.0 (lld/trunk 284614)".
+std::string lld::getLLDVersion() {
+  return "LLD " + std::string(LLD_VERSION_STRING) + getRepository();
+}
diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..85046b9
--- /dev/null
@@ -0,0 +1,30 @@
+if(NOT LLD_BUILT_STANDALONE)
+  set(tablegen_deps intrinsics_gen)
+endif()
+
+add_lld_library(lldCore
+  DefinedAtom.cpp
+  Error.cpp
+  File.cpp
+  LinkingContext.cpp
+  Reader.cpp
+  Reproduce.cpp
+  Resolver.cpp
+  SymbolTable.cpp
+  TargetOptionsCommandFlags.cpp
+  Writer.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLD_INCLUDE_DIR}/lld/Core
+
+  LINK_COMPONENTS
+    BinaryFormat
+    MC
+    Support
+
+  LINK_LIBS
+  ${LLVM_PTHREAD_LIB}
+
+  DEPENDS
+  ${tablegen_deps}
+  )
diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp
new file mode 100644 (file)
index 0000000..177cae7
--- /dev/null
@@ -0,0 +1,82 @@
+//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ErrorHandling.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+
+namespace lld {
+
+DefinedAtom::ContentPermissions DefinedAtom::permissions() const {
+  // By default base permissions on content type.
+  return permissions(this->contentType());
+}
+
+// Utility function for deriving permissions from content type
+DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
+  switch (type) {
+  case typeCode:
+  case typeResolver:
+  case typeBranchIsland:
+  case typeBranchShim:
+  case typeStub:
+  case typeStubHelper:
+  case typeMachHeader:
+    return permR_X;
+
+  case typeConstant:
+  case typeCString:
+  case typeUTF16String:
+  case typeCFI:
+  case typeLSDA:
+  case typeLiteral4:
+  case typeLiteral8:
+  case typeLiteral16:
+  case typeDTraceDOF:
+  case typeCompactUnwindInfo:
+  case typeProcessedUnwindInfo:
+  case typeObjCImageInfo:
+  case typeObjCMethodList:
+    return permR__;
+
+  case typeData:
+  case typeDataFast:
+  case typeZeroFill:
+  case typeZeroFillFast:
+  case typeObjC1Class:
+  case typeLazyPointer:
+  case typeLazyDylibPointer:
+  case typeNonLazyPointer:
+  case typeThunkTLV:
+    return permRW_;
+
+  case typeGOT:
+  case typeConstData:
+  case typeCFString:
+  case typeInitializerPtr:
+  case typeTerminatorPtr:
+  case typeCStringPtr:
+  case typeObjCClassPtr:
+  case typeObjC2CategoryList:
+  case typeInterposingTuples:
+  case typeTLVInitialData:
+  case typeTLVInitialZeroFill:
+  case typeTLVInitializerPtr:
+    return permRW_L;
+
+  case typeUnknown:
+  case typeTempLTO:
+  case typeSectCreate:
+  case typeDSOHandle:
+    return permUnknown;
+  }
+  llvm_unreachable("unknown content type");
+}
+
+} // namespace
diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp
new file mode 100644 (file)
index 0000000..6fc76f7
--- /dev/null
@@ -0,0 +1,93 @@
+//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <mutex>
+#include <string>
+#include <vector>
+
+using namespace lld;
+
+namespace {
+class _YamlReaderErrorCategory : public std::error_category {
+public:
+  const char* name() const noexcept override {
+    return "lld.yaml.reader";
+  }
+
+  std::string message(int ev) const override {
+    switch (static_cast<YamlReaderError>(ev)) {
+    case YamlReaderError::unknown_keyword:
+      return "Unknown keyword found in yaml file";
+    case YamlReaderError::illegal_value:
+      return "Bad value found in yaml file";
+    }
+    llvm_unreachable("An enumerator of YamlReaderError does not have a "
+                     "message defined.");
+  }
+};
+} // end anonymous namespace
+
+const std::error_category &lld::YamlReaderCategory() {
+  static _YamlReaderErrorCategory o;
+  return o;
+}
+
+namespace lld {
+
+/// Temporary class to enable make_dynamic_error_code() until
+/// llvm::ErrorOr<> is updated to work with error encapsulations
+/// other than error_code.
+class dynamic_error_category : public std::error_category {
+public:
+  ~dynamic_error_category() override = default;
+
+  const char *name() const noexcept override {
+    return "lld.dynamic_error";
+  }
+
+  std::string message(int ev) const override {
+    assert(ev >= 0);
+    assert(ev < (int)_messages.size());
+    // The value is an index into the string vector.
+    return _messages[ev];
+  }
+
+  int add(std::string msg) {
+    std::lock_guard<std::recursive_mutex> lock(_mutex);
+    // Value zero is always the successs value.
+    if (_messages.empty())
+      _messages.push_back("Success");
+    _messages.push_back(msg);
+    // Return the index of the string just appended.
+    return _messages.size() - 1;
+  }
+
+private:
+  std::vector<std::string> _messages;
+  std::recursive_mutex _mutex;
+};
+
+static dynamic_error_category categorySingleton;
+
+std::error_code make_dynamic_error_code(StringRef msg) {
+  return std::error_code(categorySingleton.add(msg), categorySingleton);
+}
+
+char GenericError::ID = 0;
+
+GenericError::GenericError(Twine Msg) : Msg(Msg.str()) { }
+
+void GenericError::log(raw_ostream &OS) const {
+  OS << Msg;
+}
+
+} // namespace lld
diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp
new file mode 100644 (file)
index 0000000..30ded09
--- /dev/null
@@ -0,0 +1,29 @@
+//===- Core/File.cpp - A Container of Atoms -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include <mutex>
+
+namespace lld {
+
+File::~File() = default;
+
+File::AtomVector<DefinedAtom> File::_noDefinedAtoms;
+File::AtomVector<UndefinedAtom> File::_noUndefinedAtoms;
+File::AtomVector<SharedLibraryAtom> File::_noSharedLibraryAtoms;
+File::AtomVector<AbsoluteAtom> File::_noAbsoluteAtoms;
+
+std::error_code File::parse() {
+  std::lock_guard<std::mutex> lock(_parseMutex);
+  if (!_lastError.hasValue())
+    _lastError = doParse();
+  return _lastError.getValue();
+}
+
+} // end namespace lld
diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp
new file mode 100644 (file)
index 0000000..5de863a
--- /dev/null
@@ -0,0 +1,70 @@
+//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Node.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include <algorithm>
+
+namespace lld {
+
+LinkingContext::LinkingContext() = default;
+
+LinkingContext::~LinkingContext() = default;
+
+bool LinkingContext::validate(raw_ostream &diagnostics) {
+  return validateImpl(diagnostics);
+}
+
+llvm::Error LinkingContext::writeFile(const File &linkedFile) const {
+  return this->writer().writeFile(linkedFile, _outputPath);
+}
+
+std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
+  return createEntrySymbolFile("<command line option -e>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createEntrySymbolFile(StringRef filename) const {
+  if (entrySymbolName().empty())
+    return nullptr;
+  std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename,
+                                                       File::kindEntryObject));
+  entryFile->addAtom(
+      *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
+  return std::move(entryFile);
+}
+
+std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const {
+  return createUndefinedSymbolFile("<command line option -u or --defsym>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createUndefinedSymbolFile(StringRef filename) const {
+  if (_initialUndefinedSymbols.empty())
+    return nullptr;
+  std::unique_ptr<SimpleFile> undefinedSymFile(
+    new SimpleFile(filename, File::kindUndefinedSymsObject));
+  for (StringRef undefSym : _initialUndefinedSymbols)
+    undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
+                                   *undefinedSymFile, undefSym)));
+  return std::move(undefinedSymFile);
+}
+
+void LinkingContext::createInternalFiles(
+    std::vector<std::unique_ptr<File>> &result) const {
+  if (std::unique_ptr<File> file = createEntrySymbolFile())
+    result.push_back(std::move(file));
+  if (std::unique_ptr<File> file = createUndefinedSymbolFile())
+    result.push_back(std::move(file));
+}
+
+} // end namespace lld
diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp
new file mode 100644 (file)
index 0000000..5d8bbbb
--- /dev/null
@@ -0,0 +1,114 @@
+//===- lib/Core/Reader.cpp ------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Reader.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <memory>
+
+using llvm::file_magic;
+using llvm::identify_magic;
+
+namespace lld {
+
+YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default;
+
+void Registry::add(std::unique_ptr<Reader> reader) {
+  _readers.push_back(std::move(reader));
+}
+
+void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
+  _yamlHandlers.push_back(std::move(handler));
+}
+
+ErrorOr<std::unique_ptr<File>>
+Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const {
+  // Get file magic.
+  StringRef content(mb->getBufferStart(), mb->getBufferSize());
+  file_magic fileType = identify_magic(content);
+
+  // Ask each registered reader if it can handle this file type or extension.
+  for (const std::unique_ptr<Reader> &reader : _readers) {
+    if (!reader->canParse(fileType, mb->getMemBufferRef()))
+      continue;
+    return reader->loadFile(std::move(mb), *this);
+  }
+
+  // No Reader could parse this file.
+  return make_error_code(llvm::errc::executable_format_error);
+}
+
+static const Registry::KindStrings kindStrings[] = {
+    {Reference::kindLayoutAfter, "layout-after"},
+    {Reference::kindAssociate, "associate"},
+    LLD_KIND_STRING_END};
+
+Registry::Registry() {
+  addKindTable(Reference::KindNamespace::all, Reference::KindArch::all,
+               kindStrings);
+}
+
+bool Registry::handleTaggedDoc(llvm::yaml::IO &io,
+                               const lld::File *&file) const {
+  for (const std::unique_ptr<YamlIOTaggedDocumentHandler> &h : _yamlHandlers)
+    if (h->handledDocTag(io, file))
+      return true;
+  return false;
+}
+
+void Registry::addKindTable(Reference::KindNamespace ns,
+                            Reference::KindArch arch,
+                            const KindStrings array[]) {
+  KindEntry entry = { ns, arch, array };
+  _kindEntries.push_back(entry);
+}
+
+bool Registry::referenceKindFromString(StringRef inputStr,
+                                       Reference::KindNamespace &ns,
+                                       Reference::KindArch &arch,
+                                       Reference::KindValue &value) const {
+  for (const KindEntry &entry : _kindEntries) {
+    for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+      if (!inputStr.equals(pair->name))
+        continue;
+      ns = entry.ns;
+      arch = entry.arch;
+      value = pair->value;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool Registry::referenceKindToString(Reference::KindNamespace ns,
+                                     Reference::KindArch arch,
+                                     Reference::KindValue value,
+                                     StringRef &str) const {
+  for (const KindEntry &entry : _kindEntries) {
+    if (entry.ns != ns)
+      continue;
+    if (entry.arch != arch)
+      continue;
+    for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+      if (pair->value != value)
+        continue;
+      str = pair->name;
+      return true;
+    }
+  }
+  return false;
+}
+
+} // end namespace lld
diff --git a/lib/Core/Reproduce.cpp b/lib/Core/Reproduce.cpp
new file mode 100644 (file)
index 0000000..e3629a9
--- /dev/null
@@ -0,0 +1,66 @@
+//===- Reproduce.cpp - Utilities for creating reproducers -----------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Reproduce.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace lld;
+using namespace llvm;
+using namespace llvm::sys;
+
+// Makes a given pathname an absolute path first, and then remove
+// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
+// assuming that the current directory is "/home/john/bar".
+// Returned string is a forward slash separated path even on Windows to avoid
+// a mess with backslash-as-escape and backslash-as-path-separator.
+std::string lld::relativeToRoot(StringRef Path) {
+  SmallString<128> Abs = Path;
+  if (fs::make_absolute(Abs))
+    return Path;
+  path::remove_dots(Abs, /*remove_dot_dot=*/true);
+
+  // This is Windows specific. root_name() returns a drive letter
+  // (e.g. "c:") or a UNC name (//net). We want to keep it as part
+  // of the result.
+  SmallString<128> Res;
+  StringRef Root = path::root_name(Abs);
+  if (Root.endswith(":"))
+    Res = Root.drop_back();
+  else if (Root.startswith("//"))
+    Res = Root.substr(2);
+
+  path::append(Res, path::relative_path(Abs));
+  return path::convert_to_slash(Res);
+}
+
+// Quote a given string if it contains a space character.
+std::string lld::quote(StringRef S) {
+  if (S.find(' ') == StringRef::npos)
+    return S;
+  return ("\"" + S + "\"").str();
+}
+
+std::string lld::rewritePath(StringRef S) {
+  if (fs::exists(S))
+    return relativeToRoot(S);
+  return S;
+}
+
+std::string lld::toString(opt::Arg *Arg) {
+  std::string K = Arg->getSpelling();
+  if (Arg->getNumValues() == 0)
+    return K;
+  std::string V = quote(Arg->getValue());
+  if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
+    return K + V;
+  return K + " " + V;
+}
diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp
new file mode 100644 (file)
index 0000000..e7cfaaa
--- /dev/null
@@ -0,0 +1,505 @@
+//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <utility>
+#include <vector>
+
+namespace lld {
+
+llvm::Expected<bool> Resolver::handleFile(File &file) {
+  if (auto ec = _ctx.handleLoadedFile(file))
+    return std::move(ec);
+  bool undefAdded = false;
+  for (auto &atom : file.defined().owning_ptrs())
+    doDefinedAtom(std::move(atom));
+  for (auto &atom : file.undefined().owning_ptrs()) {
+    if (doUndefinedAtom(std::move(atom)))
+      undefAdded = true;
+  }
+  for (auto &atom : file.sharedLibrary().owning_ptrs())
+    doSharedLibraryAtom(std::move(atom));
+  for (auto &atom : file.absolute().owning_ptrs())
+    doAbsoluteAtom(std::move(atom));
+  return undefAdded;
+}
+
+llvm::Expected<bool> Resolver::forEachUndefines(File &file,
+                                                UndefCallback callback) {
+  size_t i = _undefineIndex[&file];
+  bool undefAdded = false;
+  do {
+    for (; i < _undefines.size(); ++i) {
+      StringRef undefName = _undefines[i];
+      if (undefName.empty())
+        continue;
+      const Atom *atom = _symbolTable.findByName(undefName);
+      if (!isa<UndefinedAtom>(atom) || _symbolTable.isCoalescedAway(atom)) {
+        // The symbol was resolved by some other file. Cache the result.
+        _undefines[i] = "";
+        continue;
+      }
+      auto undefAddedOrError = callback(undefName);
+      if (auto ec = undefAddedOrError.takeError())
+        return std::move(ec);
+      undefAdded |= undefAddedOrError.get();
+    }
+  } while (i < _undefines.size());
+  _undefineIndex[&file] = i;
+  return undefAdded;
+}
+
+llvm::Expected<bool> Resolver::handleArchiveFile(File &file) {
+  ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
+  return forEachUndefines(file,
+                          [&](StringRef undefName) -> llvm::Expected<bool> {
+    if (File *member = archiveFile->find(undefName)) {
+      member->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      return handleFile(*member);
+    }
+    return false;
+  });
+}
+
+llvm::Error Resolver::handleSharedLibrary(File &file) {
+  // Add all the atoms from the shared library
+  SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
+  auto undefAddedOrError = handleFile(*sharedLibrary);
+  if (auto ec = undefAddedOrError.takeError())
+    return ec;
+  undefAddedOrError =
+      forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected<bool> {
+        auto atom = sharedLibrary->exports(undefName);
+        if (atom.get())
+          doSharedLibraryAtom(std::move(atom));
+        return false;
+      });
+
+  if (auto ec = undefAddedOrError.takeError())
+    return ec;
+  return llvm::Error::success();
+}
+
+bool Resolver::doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "       UndefinedAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", name=" << atom.get()->name() << "\n");
+
+  // tell symbol table
+  bool newUndefAdded = _symbolTable.add(*atom.get());
+  if (newUndefAdded)
+    _undefines.push_back(atom.get()->name());
+
+  // add to list of known atoms
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+
+  return newUndefAdded;
+}
+
+// Called on each atom when a file is added. Returns true if a given
+// atom is added to the symbol table.
+void Resolver::doDefinedAtom(OwningAtomPtr<DefinedAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "         DefinedAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", file=#"
+                    << atom.get()->file().ordinal()
+                    << ", atom=#"
+                    << atom.get()->ordinal()
+                    << ", name="
+                    << atom.get()->name()
+                    << ", type="
+                    << atom.get()->contentType()
+                    << "\n");
+
+  // An atom that should never be dead-stripped is a dead-strip root.
+  if (_ctx.deadStrip() &&
+      atom.get()->deadStrip() == DefinedAtom::deadStripNever) {
+    _deadStripRoots.insert(atom.get());
+  }
+
+  // add to list of known atoms
+  _symbolTable.add(*atom.get());
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+void Resolver::doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "   SharedLibraryAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", name="
+                    << atom.get()->name()
+                    << "\n");
+
+  // tell symbol table
+  _symbolTable.add(*atom.get());
+
+  // add to list of known atoms
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+void Resolver::doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom) {
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                    << "       AbsoluteAtom: "
+                    << llvm::format("0x%09lX", atom.get())
+                    << ", name="
+                    << atom.get()->name()
+                    << "\n");
+
+  // tell symbol table
+  if (atom.get()->scope() != Atom::scopeTranslationUnit)
+    _symbolTable.add(*atom.get());
+
+  // add to list of known atoms
+  _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+// Returns true if at least one of N previous files has created an
+// undefined symbol.
+bool Resolver::undefinesAdded(int begin, int end) {
+  std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+  for (int i = begin; i < end; ++i)
+    if (FileNode *node = dyn_cast<FileNode>(inputs[i].get()))
+      if (_newUndefinesAdded[node->getFile()])
+        return true;
+  return false;
+}
+
+File *Resolver::getFile(int &index) {
+  std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+  if ((size_t)index >= inputs.size())
+    return nullptr;
+  if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) {
+    // We are at the end of the current group. If one or more new
+    // undefined atom has been added in the last groupSize files, we
+    // reiterate over the files.
+    int size = group->getSize();
+    if (undefinesAdded(index - size, index)) {
+      index -= size;
+      return getFile(index);
+    }
+    ++index;
+    return getFile(index);
+  }
+  return cast<FileNode>(inputs[index++].get())->getFile();
+}
+
+// Keep adding atoms until _ctx.getNextFile() returns an error. This
+// function is where undefined atoms are resolved.
+bool Resolver::resolveUndefines() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Resolving undefines:\n");
+  ScopedTask task(getDefaultDomain(), "resolveUndefines");
+  int index = 0;
+  std::set<File *> seen;
+  for (;;) {
+    bool undefAdded = false;
+    DEBUG_WITH_TYPE("resolver",
+                    llvm::dbgs() << "Loading file #" << index << "\n");
+    File *file = getFile(index);
+    if (!file)
+      return true;
+    if (std::error_code ec = file->parse()) {
+      llvm::errs() << "Cannot open " + file->path()
+                   << ": " << ec.message() << "\n";
+      return false;
+    }
+    DEBUG_WITH_TYPE("resolver",
+                    llvm::dbgs() << "Loaded file: " << file->path() << "\n");
+    switch (file->kind()) {
+    case File::kindErrorObject:
+    case File::kindNormalizedObject:
+    case File::kindMachObject:
+    case File::kindCEntryObject:
+    case File::kindHeaderObject:
+    case File::kindEntryObject:
+    case File::kindUndefinedSymsObject:
+    case File::kindStubHelperObject:
+    case File::kindResolverMergedObject:
+    case File::kindSectCreateObject: {
+      // The same file may be visited more than once if the file is
+      // in --start-group and --end-group. Only library files should
+      // be processed more than once.
+      if (seen.count(file))
+        break;
+      seen.insert(file);
+      assert(!file->hasOrdinal());
+      file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      auto undefAddedOrError = handleFile(*file);
+      if (auto EC = undefAddedOrError.takeError()) {
+        // FIXME: This should be passed to logAllUnhandledErrors but it needs
+        // to be passed a Twine instead of a string.
+        llvm::errs() << "Error in " + file->path() << ": ";
+        logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+        return false;
+      }
+      undefAdded = undefAddedOrError.get();
+      break;
+    }
+    case File::kindArchiveLibrary: {
+      if (!file->hasOrdinal())
+        file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      auto undefAddedOrError = handleArchiveFile(*file);
+      if (auto EC = undefAddedOrError.takeError()) {
+        // FIXME: This should be passed to logAllUnhandledErrors but it needs
+        // to be passed a Twine instead of a string.
+        llvm::errs() << "Error in " + file->path() << ": ";
+        logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+        return false;
+      }
+      undefAdded = undefAddedOrError.get();
+      break;
+    }
+    case File::kindSharedLibrary:
+      if (!file->hasOrdinal())
+        file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+      if (auto EC = handleSharedLibrary(*file)) {
+        // FIXME: This should be passed to logAllUnhandledErrors but it needs
+        // to be passed a Twine instead of a string.
+        llvm::errs() << "Error in " + file->path() << ": ";
+        logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+        return false;
+      }
+      break;
+    }
+    _newUndefinesAdded[file] = undefAdded;
+  }
+}
+
+// switch all references to undefined or coalesced away atoms
+// to the new defined atom
+void Resolver::updateReferences() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Updating references:\n");
+  ScopedTask task(getDefaultDomain(), "updateReferences");
+  for (const OwningAtomPtr<Atom> &atom : _atoms) {
+    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) {
+      for (const Reference *ref : *defAtom) {
+        // A reference of type kindAssociate should't be updated.
+        // Instead, an atom having such reference will be removed
+        // if the target atom is coalesced away, so that they will
+        // go away as a group.
+        if (ref->kindNamespace() == lld::Reference::KindNamespace::all &&
+            ref->kindValue() == lld::Reference::kindAssociate) {
+          if (_symbolTable.isCoalescedAway(atom.get()))
+            _deadAtoms.insert(ref->target());
+          continue;
+        }
+        const Atom *newTarget = _symbolTable.replacement(ref->target());
+        const_cast<Reference *>(ref)->setTarget(newTarget);
+      }
+    }
+  }
+}
+
+// For dead code stripping, recursively mark atoms "live"
+void Resolver::markLive(const Atom *atom) {
+  // Mark the atom is live. If it's already marked live, then stop recursion.
+  auto exists = _liveAtoms.insert(atom);
+  if (!exists.second)
+    return;
+
+  // Mark all atoms it references as live
+  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+    for (const Reference *ref : *defAtom)
+      markLive(ref->target());
+    for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) {
+      const Atom *target = p.second;
+      markLive(target);
+    }
+  }
+}
+
+static bool isBackref(const Reference *ref) {
+  if (ref->kindNamespace() != lld::Reference::KindNamespace::all)
+    return false;
+  return (ref->kindValue() == lld::Reference::kindLayoutAfter);
+}
+
+// remove all atoms not actually used
+void Resolver::deadStripOptimize() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Dead stripping unused atoms:\n");
+  ScopedTask task(getDefaultDomain(), "deadStripOptimize");
+  // only do this optimization with -dead_strip
+  if (!_ctx.deadStrip())
+    return;
+
+  // Some type of references prevent referring atoms to be dead-striped.
+  // Make a reverse map of such references before traversing the graph.
+  // While traversing the list of atoms, mark AbsoluteAtoms as live
+  // in order to avoid reclaim.
+  for (const OwningAtomPtr<Atom> &atom : _atoms) {
+    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
+      for (const Reference *ref : *defAtom)
+        if (isBackref(ref))
+          _reverseRef.insert(std::make_pair(ref->target(), atom.get()));
+    if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom.get()))
+      markLive(absAtom);
+  }
+
+  // By default, shared libraries are built with all globals as dead strip roots
+  if (_ctx.globalsAreDeadStripRoots())
+    for (const OwningAtomPtr<Atom> &atom : _atoms)
+      if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
+        if (defAtom->scope() == DefinedAtom::scopeGlobal)
+          _deadStripRoots.insert(defAtom);
+
+  // Or, use list of names that are dead strip roots.
+  for (const StringRef &name : _ctx.deadStripRoots()) {
+    const Atom *symAtom = _symbolTable.findByName(name);
+    assert(symAtom);
+    _deadStripRoots.insert(symAtom);
+  }
+
+  // mark all roots as live, and recursively all atoms they reference
+  for (const Atom *dsrAtom : _deadStripRoots)
+    markLive(dsrAtom);
+
+  // now remove all non-live atoms from _atoms
+  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+                              [&](OwningAtomPtr<Atom> &a) {
+                 return _liveAtoms.count(a.get()) == 0;
+               }),
+               _atoms.end());
+}
+
+// error out if some undefines remain
+bool Resolver::checkUndefines() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Checking for undefines:\n");
+
+  // build vector of remaining undefined symbols
+  std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines();
+  if (_ctx.deadStrip()) {
+    // When dead code stripping, we don't care if dead atoms are undefined.
+    undefinedAtoms.erase(
+        std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(),
+                       [&](const Atom *a) { return _liveAtoms.count(a) == 0; }),
+        undefinedAtoms.end());
+  }
+
+  if (undefinedAtoms.empty())
+    return false;
+
+  // Warn about unresolved symbols.
+  bool foundUndefines = false;
+  for (const UndefinedAtom *undef : undefinedAtoms) {
+    // Skip over a weak symbol.
+    if (undef->canBeNull() != UndefinedAtom::canBeNullNever)
+      continue;
+
+    // If this is a library and undefined symbols are allowed on the
+    // target platform, skip over it.
+    if (isa<SharedLibraryFile>(undef->file()) && _ctx.allowShlibUndefines())
+      continue;
+
+    // If the undefine is coalesced away, skip over it.
+    if (_symbolTable.isCoalescedAway(undef))
+      continue;
+
+    // Seems like this symbol is undefined. Warn that.
+    foundUndefines = true;
+    if (_ctx.printRemainingUndefines()) {
+      llvm::errs() << "Undefined symbol: " << undef->file().path()
+                   << ": " << _ctx.demangle(undef->name())
+                   << "\n";
+    }
+  }
+  if (!foundUndefines)
+    return false;
+  if (_ctx.printRemainingUndefines())
+    llvm::errs() << "symbol(s) not found\n";
+  return true;
+}
+
+// remove from _atoms all coaleseced away atoms
+void Resolver::removeCoalescedAwayAtoms() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Removing coalesced away atoms:\n");
+  ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
+  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+                              [&](OwningAtomPtr<Atom> &a) {
+                 return _symbolTable.isCoalescedAway(a.get()) ||
+                        _deadAtoms.count(a.get());
+               }),
+               _atoms.end());
+}
+
+bool Resolver::resolve() {
+  DEBUG_WITH_TYPE("resolver",
+                  llvm::dbgs() << "******** Resolving atom references:\n");
+  if (!resolveUndefines())
+    return false;
+  updateReferences();
+  deadStripOptimize();
+  if (checkUndefines()) {
+    DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Found undefines... ");
+    if (!_ctx.allowRemainingUndefines()) {
+      DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we don't allow\n");
+      return false;
+    }
+    DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we are ok with\n");
+  }
+  removeCoalescedAwayAtoms();
+  _result->addAtoms(_atoms);
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Finished resolver\n");
+  return true;
+}
+
+void Resolver::MergedFile::addAtoms(
+                              llvm::MutableArrayRef<OwningAtomPtr<Atom>> all) {
+  ScopedTask task(getDefaultDomain(), "addAtoms");
+  DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
+
+  for (OwningAtomPtr<Atom> &atom : all) {
+#ifndef NDEBUG
+    if (auto *definedAtom = dyn_cast<DefinedAtom>(atom.get())) {
+      DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                      << llvm::format("    0x%09lX", definedAtom)
+                      << ", file=#"
+                      << definedAtom->file().ordinal()
+                      << ", atom=#"
+                      << definedAtom->ordinal()
+                      << ", name="
+                      << definedAtom->name()
+                      << ", type="
+                      << definedAtom->contentType()
+                      << "\n");
+    } else {
+      DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+                      << llvm::format("    0x%09lX", atom.get())
+                      << ", name="
+                      << atom.get()->name()
+                      << "\n");
+    }
+#endif
+    addAtom(*atom.release());
+  }
+}
+
+} // namespace lld
diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp
new file mode 100644 (file)
index 0000000..583c65a
--- /dev/null
@@ -0,0 +1,291 @@
+//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <vector>
+
+namespace lld {
+bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const DefinedAtom &atom) {
+  if (!atom.name().empty() &&
+      atom.scope() != DefinedAtom::scopeTranslationUnit) {
+    // Named atoms cannot be merged by content.
+    assert(atom.merge() != DefinedAtom::mergeByContent);
+    // Track named atoms that are not scoped to file (static).
+    return addByName(atom);
+  }
+  if (atom.merge() == DefinedAtom::mergeByContent) {
+    // Named atoms cannot be merged by content.
+    assert(atom.name().empty());
+    // Currently only read-only constants can be merged.
+    if (atom.permissions() == DefinedAtom::permR__)
+      return addByContent(atom);
+    // TODO: support mergeByContent of data atoms by comparing content & fixups.
+  }
+  return false;
+}
+
+enum NameCollisionResolution {
+  NCR_First,
+  NCR_Second,
+  NCR_DupDef,
+  NCR_DupUndef,
+  NCR_DupShLib,
+  NCR_Error
+};
+
+static NameCollisionResolution cases[4][4] = {
+  //regular     absolute    undef      sharedLib
+  {
+    // first is regular
+    NCR_DupDef, NCR_Error,   NCR_First, NCR_First
+  },
+  {
+    // first is absolute
+    NCR_Error,  NCR_Error,  NCR_First, NCR_First
+  },
+  {
+    // first is undef
+    NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second
+  },
+  {
+    // first is sharedLib
+    NCR_Second, NCR_Second, NCR_First, NCR_DupShLib
+  }
+};
+
+static NameCollisionResolution collide(Atom::Definition first,
+                                       Atom::Definition second) {
+  return cases[first][second];
+}
+
+enum MergeResolution {
+  MCR_First,
+  MCR_Second,
+  MCR_Largest,
+  MCR_SameSize,
+  MCR_Error
+};
+
+static MergeResolution mergeCases[][6] = {
+  // no          tentative      weak          weakAddress   sameNameAndSize largest
+  {MCR_Error,    MCR_First,     MCR_First,    MCR_First,    MCR_SameSize,   MCR_Largest},  // no
+  {MCR_Second,   MCR_Largest,   MCR_Second,   MCR_Second,   MCR_SameSize,   MCR_Largest},  // tentative
+  {MCR_Second,   MCR_First,     MCR_First,    MCR_Second,   MCR_SameSize,   MCR_Largest},  // weak
+  {MCR_Second,   MCR_First,     MCR_First,    MCR_First,    MCR_SameSize,   MCR_Largest},  // weakAddress
+  {MCR_SameSize, MCR_SameSize,  MCR_SameSize, MCR_SameSize, MCR_SameSize,   MCR_SameSize}, // sameSize
+  {MCR_Largest,  MCR_Largest,   MCR_Largest,  MCR_Largest,  MCR_SameSize,   MCR_Largest},  // largest
+};
+
+static MergeResolution mergeSelect(DefinedAtom::Merge first,
+                                   DefinedAtom::Merge second) {
+  assert(first != DefinedAtom::mergeByContent);
+  assert(second != DefinedAtom::mergeByContent);
+  return mergeCases[first][second];
+}
+
+bool SymbolTable::addByName(const Atom &newAtom) {
+  StringRef name = newAtom.name();
+  assert(!name.empty());
+  const Atom *existing = findByName(name);
+  if (existing == nullptr) {
+    // Name is not in symbol table yet, add it associate with this atom.
+    _nameTable[name] = &newAtom;
+    return true;
+  }
+
+  // Do nothing if the same object is added more than once.
+  if (existing == &newAtom)
+    return false;
+
+  // Name is already in symbol table and associated with another atom.
+  bool useNew = true;
+  switch (collide(existing->definition(), newAtom.definition())) {
+  case NCR_First:
+    useNew = false;
+    break;
+  case NCR_Second:
+    useNew = true;
+    break;
+  case NCR_DupDef: {
+    const auto *existingDef = cast<DefinedAtom>(existing);
+    const auto *newDef = cast<DefinedAtom>(&newAtom);
+    switch (mergeSelect(existingDef->merge(), newDef->merge())) {
+    case MCR_First:
+      useNew = false;
+      break;
+    case MCR_Second:
+      useNew = true;
+      break;
+    case MCR_Largest: {
+      uint64_t existingSize = existingDef->sectionSize();
+      uint64_t newSize = newDef->sectionSize();
+      useNew = (newSize >= existingSize);
+      break;
+    }
+    case MCR_SameSize: {
+      uint64_t existingSize = existingDef->sectionSize();
+      uint64_t newSize = newDef->sectionSize();
+      if (existingSize == newSize) {
+        useNew = true;
+        break;
+      }
+      llvm::errs() << "Size mismatch: "
+                   << existing->name() << " (" << existingSize << ") "
+                   << newAtom.name() << " (" << newSize << ")\n";
+      LLVM_FALLTHROUGH;
+    }
+    case MCR_Error:
+      llvm::errs() << "Duplicate symbols: "
+                   << existing->name()
+                   << ":"
+                   << existing->file().path()
+                   << " and "
+                   << newAtom.name()
+                   << ":"
+                   << newAtom.file().path()
+                   << "\n";
+      llvm::report_fatal_error("duplicate symbol error");
+      break;
+    }
+    break;
+  }
+  case NCR_DupUndef: {
+    const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing);
+    const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom);
+
+    bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
+    if (sameCanBeNull)
+      useNew = false;
+    else
+      useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
+    break;
+  }
+  case NCR_DupShLib: {
+    useNew = false;
+    break;
+  }
+  case NCR_Error:
+    llvm::errs() << "SymbolTable: error while merging " << name << "\n";
+    llvm::report_fatal_error("duplicate symbol error");
+    break;
+  }
+
+  if (useNew) {
+    // Update name table to use new atom.
+    _nameTable[name] = &newAtom;
+    // Add existing atom to replacement table.
+    _replacedAtoms[existing] = &newAtom;
+  } else {
+    // New atom is not being used.  Add it to replacement table.
+    _replacedAtoms[&newAtom] = existing;
+  }
+  return false;
+}
+
+unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) {
+  auto content = atom->rawContent();
+  return llvm::hash_combine(atom->size(),
+                            atom->contentType(),
+                            llvm::hash_combine_range(content.begin(),
+                                                     content.end()));
+}
+
+bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l,
+                                           const DefinedAtom * const r) {
+  if (l == r)
+    return true;
+  if (l == getEmptyKey() || r == getEmptyKey())
+    return false;
+  if (l == getTombstoneKey() || r == getTombstoneKey())
+    return false;
+  if (l->contentType() != r->contentType())
+    return false;
+  if (l->size() != r->size())
+    return false;
+  if (l->sectionChoice() != r->sectionChoice())
+    return false;
+  if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) {
+    if (!l->customSectionName().equals(r->customSectionName()))
+      return false;
+  }
+  ArrayRef<uint8_t> lc = l->rawContent();
+  ArrayRef<uint8_t> rc = r->rawContent();
+  return memcmp(lc.data(), rc.data(), lc.size()) == 0;
+}
+
+bool SymbolTable::addByContent(const DefinedAtom &newAtom) {
+  AtomContentSet::iterator pos = _contentTable.find(&newAtom);
+  if (pos == _contentTable.end()) {
+    _contentTable.insert(&newAtom);
+    return true;
+  }
+  const Atom* existing = *pos;
+  // New atom is not being used.  Add it to replacement table.
+  _replacedAtoms[&newAtom] = existing;
+  return false;
+}
+
+const Atom *SymbolTable::findByName(StringRef sym) {
+  NameToAtom::iterator pos = _nameTable.find(sym);
+  if (pos == _nameTable.end())
+    return nullptr;
+  return pos->second;
+}
+
+const Atom *SymbolTable::replacement(const Atom *atom) {
+  // Find the replacement for a given atom. Atoms in _replacedAtoms
+  // may be chained, so find the last one.
+  for (;;) {
+    AtomToAtom::iterator pos = _replacedAtoms.find(atom);
+    if (pos == _replacedAtoms.end())
+      return atom;
+    atom = pos->second;
+  }
+}
+
+bool SymbolTable::isCoalescedAway(const Atom *atom) {
+  return _replacedAtoms.count(atom) > 0;
+}
+
+std::vector<const UndefinedAtom *> SymbolTable::undefines() {
+  std::vector<const UndefinedAtom *> ret;
+  for (auto it : _nameTable) {
+    const Atom *atom = it.second;
+    assert(atom != nullptr);
+    if (const auto *undef = dyn_cast<const UndefinedAtom>(atom))
+      if (_replacedAtoms.count(undef) == 0)
+        ret.push_back(undef);
+  }
+  return ret;
+}
+
+} // namespace lld
diff --git a/lib/Core/TargetOptionsCommandFlags.cpp b/lib/Core/TargetOptionsCommandFlags.cpp
new file mode 100644 (file)
index 0000000..e0f2676
--- /dev/null
@@ -0,0 +1,32 @@
+//===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exists as a place for global variables defined in LLVM's
+// CodeGen/CommandFlags.h. By putting the resulting object file in
+// an archive and linking with it, the definitions will automatically be
+// included when needed and skipped when already present.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/TargetOptionsCommandFlags.h"
+
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/Target/TargetOptions.h"
+
+// Define an externally visible version of
+// InitTargetOptionsFromCodeGenFlags, so that its functionality can be
+// used without having to include llvm/CodeGen/CommandFlags.h, which
+// would lead to multiple definitions of the command line flags.
+llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
+  return ::InitTargetOptionsFromCodeGenFlags();
+}
+
+llvm::CodeModel::Model lld::GetCodeModelFromCMModel() {
+  return CMModel;
+}
diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp
new file mode 100644 (file)
index 0000000..51f95bc
--- /dev/null
@@ -0,0 +1,18 @@
+//===- lib/Core/Writer.cpp ------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Writer.h"
+
+namespace lld {
+
+Writer::Writer() = default;
+
+Writer::~Writer() = default;
+
+} // end namespace lld
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..be75872
--- /dev/null
@@ -0,0 +1,24 @@
+set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
+tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(DriverOptionsTableGen)
+
+add_lld_library(lldDriver
+  DarwinLdDriver.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLD_INCLUDE_DIR}/lld/Driver
+
+  LINK_COMPONENTS
+    Object
+    Option
+    Support
+
+  LINK_LIBS
+    lldConfig
+    lldMachO
+    lldCore
+    lldReaderWriter
+    lldYAML
+  )
+
+add_dependencies(lldDriver DriverOptionsTableGen)
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
new file mode 100644 (file)
index 0000000..f564d8c
--- /dev/null
@@ -0,0 +1,1239 @@
+//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for darwin's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Node.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in DarwinLdOptions.td
+enum {
+  OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
+               HELP, META, VALUES)                                             \
+  OPT_##ID,
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in DarwinLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "DarwinLdOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in DarwinLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
+               HELPTEXT, METAVAR, VALUES)                                      \
+  {PREFIX,      NAME,      HELPTEXT,                                           \
+   METAVAR,     OPT_##ID,  llvm::opt::Option::KIND##Class,                     \
+   PARAM,       FLAGS,     OPT_##GROUP,                                        \
+   OPT_##ALIAS, ALIASARGS, VALUES},
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class DarwinLdOptTable : public llvm::opt::OptTable {
+public:
+  DarwinLdOptTable() : OptTable(infoTable) {}
+};
+
+static std::vector<std::unique_ptr<File>>
+makeErrorFile(StringRef path, std::error_code ec) {
+  std::vector<std::unique_ptr<File>> result;
+  result.push_back(llvm::make_unique<ErrorFile>(path, ec));
+  return result;
+}
+
+static std::vector<std::unique_ptr<File>>
+parseMemberFiles(std::unique_ptr<File> file) {
+  std::vector<std::unique_ptr<File>> members;
+  if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) {
+    if (std::error_code ec = archive->parseAllMembers(members))
+      return makeErrorFile(file->path(), ec);
+  } else {
+    members.push_back(std::move(file));
+  }
+  return members;
+}
+
+std::vector<std::unique_ptr<File>>
+loadFile(MachOLinkingContext &ctx, StringRef path,
+         raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
+  if (ctx.logInputFiles())
+    diag << path << "\n";
+
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
+  if (std::error_code ec = mbOrErr.getError())
+    return makeErrorFile(path, ec);
+  ErrorOr<std::unique_ptr<File>> fileOrErr =
+      ctx.registry().loadFile(std::move(mbOrErr.get()));
+  if (std::error_code ec = fileOrErr.getError())
+    return makeErrorFile(path, ec);
+  std::unique_ptr<File> &file = fileOrErr.get();
+
+  // If file is a dylib, inform LinkingContext about it.
+  if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(file.get())) {
+    if (std::error_code ec = shl->parse())
+      return makeErrorFile(path, ec);
+    ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile *>(shl),
+                      upwardDylib);
+  }
+  if (wholeArchive)
+    return parseMemberFiles(std::move(file));
+  std::vector<std::unique_ptr<File>> files;
+  files.push_back(std::move(file));
+  return files;
+}
+
+} // end anonymous namespace
+
+// Test may be running on Windows. Canonicalize the path
+// separator to '/' to get consistent outputs for tests.
+static std::string canonicalizePath(StringRef path) {
+  char sep = llvm::sys::path::get_separator().front();
+  if (sep != '/') {
+    std::string fixedPath = path;
+    std::replace(fixedPath.begin(), fixedPath.end(), sep, '/');
+    return fixedPath;
+  } else {
+    return path;
+  }
+}
+
+static void addFile(StringRef path, MachOLinkingContext &ctx,
+                    bool loadWholeArchive,
+                    bool upwardDylib, raw_ostream &diag) {
+  std::vector<std::unique_ptr<File>> files =
+      loadFile(ctx, path, diag, loadWholeArchive, upwardDylib);
+  for (std::unique_ptr<File> &file : files)
+    ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+}
+
+// Export lists are one symbol per line.  Blank lines are ignored.
+// Trailing comments start with #.
+static std::error_code parseExportsList(StringRef exportFilePath,
+                                        MachOLinkingContext &ctx,
+                                        raw_ostream &diagnostics) {
+  // Map in export list file.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+                                   MemoryBuffer::getFileOrSTDIN(exportFilePath);
+  if (std::error_code ec = mb.getError())
+    return ec;
+  ctx.addInputFileDependency(exportFilePath);
+  StringRef buffer = mb->get()->getBuffer();
+  while (!buffer.empty()) {
+    // Split off each line in the file.
+    std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+    StringRef line = lineAndRest.first;
+    // Ignore trailing # comments.
+    std::pair<StringRef, StringRef> symAndComment = line.split('#');
+    StringRef sym = symAndComment.first.trim();
+    if (!sym.empty())
+      ctx.addExportSymbol(sym);
+    buffer = lineAndRest.second;
+  }
+  return std::error_code();
+}
+
+/// Order files are one symbol per line. Blank lines are ignored.
+/// Trailing comments start with #. Symbol names can be prefixed with an
+/// architecture name and/or .o leaf name.  Examples:
+///     _foo
+///     bar.o:_bar
+///     libfrob.a(bar.o):_bar
+///     x86_64:_foo64
+static std::error_code parseOrderFile(StringRef orderFilePath,
+                                      MachOLinkingContext &ctx,
+                                      raw_ostream &diagnostics) {
+  // Map in order file.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+                                   MemoryBuffer::getFileOrSTDIN(orderFilePath);
+  if (std::error_code ec = mb.getError())
+    return ec;
+  ctx.addInputFileDependency(orderFilePath);
+  StringRef buffer = mb->get()->getBuffer();
+  while (!buffer.empty()) {
+    // Split off each line in the file.
+    std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+    StringRef line = lineAndRest.first;
+    buffer = lineAndRest.second;
+    // Ignore trailing # comments.
+    std::pair<StringRef, StringRef> symAndComment = line.split('#');
+    if (symAndComment.first.empty())
+      continue;
+    StringRef sym = symAndComment.first.trim();
+    if (sym.empty())
+      continue;
+    // Check for prefix.
+    StringRef prefix;
+    std::pair<StringRef, StringRef> prefixAndSym = sym.split(':');
+    if (!prefixAndSym.second.empty()) {
+      sym = prefixAndSym.second;
+      prefix = prefixAndSym.first;
+      if (!prefix.endswith(".o") && !prefix.endswith(".o)")) {
+        // If arch name prefix does not match arch being linked, ignore symbol.
+        if (!ctx.archName().equals(prefix))
+          continue;
+        prefix = "";
+      }
+    } else
+     sym = prefixAndSym.first;
+    if (!sym.empty()) {
+      ctx.appendOrderedSymbol(sym, prefix);
+      //llvm::errs() << sym << ", prefix=" << prefix << "\n";
+    }
+  }
+  return std::error_code();
+}
+
+//
+// There are two variants of the  -filelist option:
+//
+//   -filelist <path>
+// In this variant, the path is to a text file which contains one file path
+// per line.  There are no comments or trimming of whitespace.
+//
+//   -fileList <path>,<dir>
+// In this variant, the path is to a text file which contains a partial path
+// per line. The <dir> prefix is prepended to each partial path.
+//
+static llvm::Error loadFileList(StringRef fileListPath,
+                                MachOLinkingContext &ctx, bool forceLoad,
+                                raw_ostream &diagnostics) {
+  // If there is a comma, split off <dir>.
+  std::pair<StringRef, StringRef> opt = fileListPath.split(',');
+  StringRef filePath = opt.first;
+  StringRef dirName = opt.second;
+  ctx.addInputFileDependency(filePath);
+  // Map in file list file.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+                                        MemoryBuffer::getFileOrSTDIN(filePath);
+  if (std::error_code ec = mb.getError())
+    return llvm::errorCodeToError(ec);
+  StringRef buffer = mb->get()->getBuffer();
+  while (!buffer.empty()) {
+    // Split off each line in the file.
+    std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+    StringRef line = lineAndRest.first;
+    StringRef path;
+    if (!dirName.empty()) {
+      // If there is a <dir> then prepend dir to each line.
+      SmallString<256> fullPath;
+      fullPath.assign(dirName);
+      llvm::sys::path::append(fullPath, Twine(line));
+      path = ctx.copy(fullPath.str());
+    } else {
+      // No <dir> use whole line as input file path.
+      path = ctx.copy(line);
+    }
+    if (!ctx.pathExists(path)) {
+      return llvm::make_error<GenericError>(Twine("File not found '")
+                                            + path
+                                            + "'");
+    }
+    if (ctx.testingFileUsage()) {
+      diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
+    }
+    addFile(path, ctx, forceLoad, false, diagnostics);
+    buffer = lineAndRest.second;
+  }
+  return llvm::Error::success();
+}
+
+/// Parse number assuming it is base 16, but allow 0x prefix.
+static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
+  if (numStr.startswith_lower("0x"))
+    numStr = numStr.drop_front(2);
+  return numStr.getAsInteger(16, baseAddress);
+}
+
+static void parseLLVMOptions(const LinkingContext &ctx) {
+  // Honor -mllvm
+  if (!ctx.llvmOptions().empty()) {
+    unsigned numArgs = ctx.llvmOptions().size();
+    auto **args = new const char *[numArgs + 2];
+    args[0] = "lld (LLVM option parsing)";
+    for (unsigned i = 0; i != numArgs; ++i)
+      args[i + 1] = ctx.llvmOptions()[i];
+    args[numArgs + 1] = nullptr;
+    llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
+  }
+}
+
+namespace lld {
+namespace mach_o {
+
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
+           raw_ostream &diagnostics) {
+  // Parse command line options using DarwinLdOptions.td
+  DarwinLdOptTable table;
+  unsigned missingIndex;
+  unsigned missingCount;
+  llvm::opt::InputArgList parsedArgs =
+      table.ParseArgs(args.slice(1), missingIndex, missingCount);
+  if (missingCount) {
+    diagnostics << "error: missing arg value for '"
+                << parsedArgs.getArgString(missingIndex) << "' expected "
+                << missingCount << " argument(s).\n";
+    return false;
+  }
+
+  for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) {
+    diagnostics << "warning: ignoring unknown argument: "
+                << unknownArg->getAsString(parsedArgs) << "\n";
+  }
+
+  // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
+  llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
+  bool isStaticExecutable = false;
+  if (llvm::opt::Arg *kind = parsedArgs.getLastArg(
+          OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) {
+    switch (kind->getOption().getID()) {
+    case OPT_dylib:
+      fileType = llvm::MachO::MH_DYLIB;
+      break;
+    case OPT_relocatable:
+      fileType = llvm::MachO::MH_OBJECT;
+      break;
+    case OPT_bundle:
+      fileType = llvm::MachO::MH_BUNDLE;
+      break;
+    case OPT_static:
+      fileType = llvm::MachO::MH_EXECUTE;
+      isStaticExecutable = true;
+      break;
+    case OPT_preload:
+      fileType = llvm::MachO::MH_PRELOAD;
+      break;
+    }
+  }
+
+  // Handle -arch xxx
+  MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown;
+  if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) {
+    arch = MachOLinkingContext::archFromName(archStr->getValue());
+    if (arch == MachOLinkingContext::arch_unknown) {
+      diagnostics << "error: unknown arch named '" << archStr->getValue()
+                  << "'\n";
+      return false;
+    }
+  }
+  // If no -arch specified, scan input files to find first non-fat .o file.
+  if (arch == MachOLinkingContext::arch_unknown) {
+    for (auto &inFile : parsedArgs.filtered(OPT_INPUT)) {
+      // This is expensive because it opens and maps the file.  But that is
+      // ok because no -arch is rare.
+      if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
+        break;
+    }
+    if (arch == MachOLinkingContext::arch_unknown &&
+        !parsedArgs.getLastArg(OPT_test_file_usage)) {
+      // If no -arch and no options at all, print usage message.
+      if (parsedArgs.size() == 0)
+        table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false);
+      else
+        diagnostics << "error: -arch not specified and could not be inferred\n";
+      return false;
+    }
+  }
+
+  // Handle -macosx_version_min or -ios_version_min
+  MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown;
+  uint32_t minOSVersion = 0;
+  if (llvm::opt::Arg *minOS =
+          parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min,
+                                OPT_ios_simulator_version_min)) {
+    switch (minOS->getOption().getID()) {
+    case OPT_macosx_version_min:
+      os = MachOLinkingContext::OS::macOSX;
+      if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+                                                  minOSVersion)) {
+        diagnostics << "error: malformed macosx_version_min value\n";
+        return false;
+      }
+      break;
+    case OPT_ios_version_min:
+      os = MachOLinkingContext::OS::iOS;
+      if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+                                                  minOSVersion)) {
+        diagnostics << "error: malformed ios_version_min value\n";
+        return false;
+      }
+      break;
+    case OPT_ios_simulator_version_min:
+      os = MachOLinkingContext::OS::iOS_simulator;
+      if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+                                                  minOSVersion)) {
+        diagnostics << "error: malformed ios_simulator_version_min value\n";
+        return false;
+      }
+      break;
+    }
+  } else {
+    // No min-os version on command line, check environment variables
+  }
+
+  // Handle export_dynamic
+  // FIXME: Should we warn when this applies to something other than a static
+  // executable or dylib?  Those are the only cases where this has an effect.
+  // Note, this has to come before ctx.configure() so that we get the correct
+  // value for _globalsAreDeadStripRoots.
+  bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic);
+
+  // Now that there's enough information parsed in, let the linking context
+  // set up default values.
+  ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols);
+
+  // Handle -e xxx
+  if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry))
+    ctx.setEntrySymbolName(entry->getValue());
+
+  // Handle -o xxx
+  if (llvm::opt::Arg *outpath = parsedArgs.getLastArg(OPT_output))
+    ctx.setOutputPath(outpath->getValue());
+  else
+    ctx.setOutputPath("a.out");
+
+  // Handle -image_base XXX and -seg1addr XXXX
+  if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) {
+    uint64_t baseAddress;
+    if (parseNumberBase16(imageBase->getValue(), baseAddress)) {
+      diagnostics << "error: image_base expects a hex number\n";
+      return false;
+    } else if (baseAddress < ctx.pageZeroSize()) {
+      diagnostics << "error: image_base overlaps with __PAGEZERO\n";
+      return false;
+    } else if (baseAddress % ctx.pageSize()) {
+      diagnostics << "error: image_base must be a multiple of page size ("
+                  << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
+      return false;
+    }
+
+    ctx.setBaseAddress(baseAddress);
+  }
+
+  // Handle -dead_strip
+  if (parsedArgs.getLastArg(OPT_dead_strip))
+    ctx.setDeadStripping(true);
+
+  bool globalWholeArchive = false;
+  // Handle -all_load
+  if (parsedArgs.getLastArg(OPT_all_load))
+    globalWholeArchive = true;
+
+  // Handle -install_name
+  if (llvm::opt::Arg *installName = parsedArgs.getLastArg(OPT_install_name))
+    ctx.setInstallName(installName->getValue());
+  else
+    ctx.setInstallName(ctx.outputPath());
+
+  // Handle -mark_dead_strippable_dylib
+  if (parsedArgs.getLastArg(OPT_mark_dead_strippable_dylib))
+    ctx.setDeadStrippableDylib(true);
+
+  // Handle -compatibility_version and -current_version
+  if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) {
+    if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+      diagnostics
+          << "error: -compatibility_version can only be used with -dylib\n";
+      return false;
+    }
+    uint32_t parsedVers;
+    if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+      diagnostics << "error: -compatibility_version value is malformed\n";
+      return false;
+    }
+    ctx.setCompatibilityVersion(parsedVers);
+  }
+
+  if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) {
+    if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+      diagnostics << "-current_version can only be used with -dylib\n";
+      return false;
+    }
+    uint32_t parsedVers;
+    if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+      diagnostics << "error: -current_version value is malformed\n";
+      return false;
+    }
+    ctx.setCurrentVersion(parsedVers);
+  }
+
+  // Handle -bundle_loader
+  if (llvm::opt::Arg *loader = parsedArgs.getLastArg(OPT_bundle_loader))
+    ctx.setBundleLoader(loader->getValue());
+
+  // Handle -sectalign segname sectname align
+  for (auto &alignArg : parsedArgs.filtered(OPT_sectalign)) {
+    const char* segName   = alignArg->getValue(0);
+    const char* sectName  = alignArg->getValue(1);
+    const char* alignStr  = alignArg->getValue(2);
+    if ((alignStr[0] == '0') && (alignStr[1] == 'x'))
+      alignStr += 2;
+    unsigned long long alignValue;
+    if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) {
+      diagnostics << "error: -sectalign alignment value '"
+                  << alignStr << "' not a valid number\n";
+      return false;
+    }
+    uint16_t align = 1 << llvm::countTrailingZeros(alignValue);
+    if (!llvm::isPowerOf2_64(alignValue)) {
+      diagnostics << "warning: alignment for '-sectalign "
+                  << segName << " " << sectName
+                  << llvm::format(" 0x%llX", alignValue)
+                  << "' is not a power of two, using "
+                  << llvm::format("0x%08X", align) << "\n";
+    }
+    ctx.addSectionAlignment(segName, sectName, align);
+  }
+
+  // Handle -mllvm
+  for (auto &llvmArg : parsedArgs.filtered(OPT_mllvm)) {
+    ctx.appendLLVMOption(llvmArg->getValue());
+  }
+
+  // Handle -print_atoms
+  if (parsedArgs.getLastArg(OPT_print_atoms))
+    ctx.setPrintAtoms();
+
+  // Handle -t (trace) option.
+  if (parsedArgs.getLastArg(OPT_t))
+    ctx.setLogInputFiles(true);
+
+  // Handle -demangle option.
+  if (parsedArgs.getLastArg(OPT_demangle))
+    ctx.setDemangleSymbols(true);
+
+  // Handle -keep_private_externs
+  if (parsedArgs.getLastArg(OPT_keep_private_externs)) {
+    ctx.setKeepPrivateExterns(true);
+    if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+      diagnostics << "warning: -keep_private_externs only used in -r mode\n";
+  }
+
+  // Handle -dependency_info <path> used by Xcode.
+  if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) {
+    if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) {
+      diagnostics << "warning: " << ec.message()
+                  << ", processing '-dependency_info "
+                  << depInfo->getValue()
+                  << "'\n";
+    }
+  }
+
+  // In -test_file_usage mode, we'll be given an explicit list of paths that
+  // exist. We'll also be expected to print out information about how we located
+  // libraries and so on that the user specified, but not to actually do any
+  // linking.
+  if (parsedArgs.getLastArg(OPT_test_file_usage)) {
+    ctx.setTestingFileUsage();
+
+    // With paths existing by fiat, linking is not going to end well.
+    ctx.setDoNothing(true);
+
+    // Only bother looking for an existence override if we're going to use it.
+    for (auto existingPath : parsedArgs.filtered(OPT_path_exists)) {
+      ctx.addExistingPathForDebug(existingPath->getValue());
+    }
+  }
+
+  // Register possible input file parsers.
+  if (!ctx.doNothing()) {
+    ctx.registry().addSupportMachOObjects(ctx);
+    ctx.registry().addSupportArchives(ctx.logInputFiles());
+    ctx.registry().addSupportYamlFiles();
+  }
+
+  // Now construct the set of library search directories, following ld64's
+  // baroque set of accumulated hacks. Mostly, the algorithm constructs
+  //     { syslibroots } x { libpaths }
+  //
+  // Unfortunately, there are numerous exceptions:
+  //   1. Only absolute paths get modified by syslibroot options.
+  //   2. If there is just 1 -syslibroot, system paths not found in it are
+  //      skipped.
+  //   3. If the last -syslibroot is "/", all of them are ignored entirely.
+  //   4. If { syslibroots } x path ==  {}, the original path is kept.
+  std::vector<StringRef> sysLibRoots;
+  for (auto syslibRoot : parsedArgs.filtered(OPT_syslibroot)) {
+    sysLibRoots.push_back(syslibRoot->getValue());
+  }
+  if (!sysLibRoots.empty()) {
+    // Ignore all if last -syslibroot is "/".
+    if (sysLibRoots.back() != "/")
+      ctx.setSysLibRoots(sysLibRoots);
+  }
+
+  // Paths specified with -L come first, and are not considered system paths for
+  // the case where there is precisely 1 -syslibroot.
+  for (auto libPath : parsedArgs.filtered(OPT_L)) {
+    ctx.addModifiedSearchDir(libPath->getValue());
+  }
+
+  // Process -F directories (where to look for frameworks).
+  for (auto fwPath : parsedArgs.filtered(OPT_F)) {
+    ctx.addFrameworkSearchDir(fwPath->getValue());
+  }
+
+  // -Z suppresses the standard search paths.
+  if (!parsedArgs.hasArg(OPT_Z)) {
+    ctx.addModifiedSearchDir("/usr/lib", true);
+    ctx.addModifiedSearchDir("/usr/local/lib", true);
+    ctx.addFrameworkSearchDir("/Library/Frameworks", true);
+    ctx.addFrameworkSearchDir("/System/Library/Frameworks", true);
+  }
+
+  // Now that we've constructed the final set of search paths, print out those
+  // search paths in verbose mode.
+  if (parsedArgs.getLastArg(OPT_v)) {
+    diagnostics << "Library search paths:\n";
+    for (auto path : ctx.searchDirs()) {
+      diagnostics << "    " << path << '\n';
+    }
+    diagnostics << "Framework search paths:\n";
+    for (auto path : ctx.frameworkDirs()) {
+      diagnostics << "    " << path << '\n';
+    }
+  }
+
+  // Handle -exported_symbols_list <file>
+  for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+      diagnostics << "error: -exported_symbols_list cannot be combined "
+                  << "with -unexported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+    if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+                                              diagnostics)) {
+      diagnostics << "error: " << ec.message()
+                  << ", processing '-exported_symbols_list "
+                  << expFile->getValue()
+                  << "'\n";
+      return false;
+    }
+  }
+
+  // Handle -exported_symbol <symbol>
+  for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+      diagnostics << "error: -exported_symbol cannot be combined "
+                  << "with -unexported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+    ctx.addExportSymbol(symbol->getValue());
+  }
+
+  // Handle -unexported_symbols_list <file>
+  for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+      diagnostics << "error: -unexported_symbols_list cannot be combined "
+                  << "with -exported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+    if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+                                              diagnostics)) {
+      diagnostics << "error: " << ec.message()
+                  << ", processing '-unexported_symbols_list "
+                  << expFile->getValue()
+                  << "'\n";
+      return false;
+    }
+  }
+
+  // Handle -unexported_symbol <symbol>
+  for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) {
+    if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+      diagnostics << "error: -unexported_symbol cannot be combined "
+                  << "with -exported_symbol[s_list]\n";
+       return false;
+    }
+    ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+    ctx.addExportSymbol(symbol->getValue());
+  }
+
+  // Handle obosolete -multi_module and -single_module
+  if (llvm::opt::Arg *mod =
+          parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) {
+    if (mod->getOption().getID() == OPT_multi_module) {
+      diagnostics << "warning: -multi_module is obsolete and being ignored\n";
+    }
+    else {
+      if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+        diagnostics << "warning: -single_module being ignored. "
+                       "It is only for use when producing a dylib\n";
+      }
+    }
+  }
+
+  // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only
+  if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) {
+    diagnostics << "error: -objc_gc_compaction is not supported\n";
+    return false;
+  }
+
+  if (parsedArgs.getLastArg(OPT_objc_gc)) {
+    diagnostics << "error: -objc_gc is not supported\n";
+    return false;
+  }
+
+  if (parsedArgs.getLastArg(OPT_objc_gc_only)) {
+    diagnostics << "error: -objc_gc_only is not supported\n";
+    return false;
+  }
+
+  // Handle -pie or -no_pie
+  if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) {
+    switch (ctx.outputMachOType()) {
+    case llvm::MachO::MH_EXECUTE:
+      switch (ctx.os()) {
+      case MachOLinkingContext::OS::macOSX:
+        if ((minOSVersion < 0x000A0500) &&
+            (pie->getOption().getID() == OPT_pie)) {
+          diagnostics << "-pie can only be used when targeting "
+                         "Mac OS X 10.5 or later\n";
+          return false;
+        }
+        break;
+      case MachOLinkingContext::OS::iOS:
+        if ((minOSVersion < 0x00040200) &&
+            (pie->getOption().getID() == OPT_pie)) {
+          diagnostics << "-pie can only be used when targeting "
+                         "iOS 4.2 or later\n";
+          return false;
+        }
+        break;
+      case MachOLinkingContext::OS::iOS_simulator:
+        if (pie->getOption().getID() == OPT_no_pie) {
+          diagnostics << "iOS simulator programs must be built PIE\n";
+          return false;
+        }
+        break;
+      case MachOLinkingContext::OS::unknown:
+        break;
+      }
+      ctx.setPIE(pie->getOption().getID() == OPT_pie);
+      break;
+    case llvm::MachO::MH_PRELOAD:
+      break;
+    case llvm::MachO::MH_DYLIB:
+    case llvm::MachO::MH_BUNDLE:
+      diagnostics << "warning: " << pie->getSpelling() << " being ignored. "
+                  << "It is only used when linking main executables\n";
+      break;
+    default:
+      diagnostics << pie->getSpelling()
+                  << " can only used when linking main executables\n";
+      return false;
+    }
+  }
+
+  // Handle -version_load_command or -no_version_load_command
+  {
+    bool flagOn = false;
+    bool flagOff = false;
+    if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command,
+                                          OPT_no_version_load_command)) {
+      flagOn = arg->getOption().getID() == OPT_version_load_command;
+      flagOff = arg->getOption().getID() == OPT_no_version_load_command;
+    }
+
+    // default to adding version load command for dynamic code,
+    // static code must opt-in
+    switch (ctx.outputMachOType()) {
+      case llvm::MachO::MH_OBJECT:
+        ctx.setGenerateVersionLoadCommand(false);
+        break;
+      case llvm::MachO::MH_EXECUTE:
+        // dynamic executables default to generating a version load command,
+        // while static exectuables only generate it if required.
+        if (isStaticExecutable) {
+          if (flagOn)
+            ctx.setGenerateVersionLoadCommand(true);
+        } else {
+          if (!flagOff)
+            ctx.setGenerateVersionLoadCommand(true);
+        }
+        break;
+      case llvm::MachO::MH_PRELOAD:
+      case llvm::MachO::MH_KEXT_BUNDLE:
+        if (flagOn)
+          ctx.setGenerateVersionLoadCommand(true);
+        break;
+      case llvm::MachO::MH_DYLINKER:
+      case llvm::MachO::MH_DYLIB:
+      case llvm::MachO::MH_BUNDLE:
+        if (!flagOff)
+          ctx.setGenerateVersionLoadCommand(true);
+        break;
+      case llvm::MachO::MH_FVMLIB:
+      case llvm::MachO::MH_DYLDLINK:
+      case llvm::MachO::MH_DYLIB_STUB:
+      case llvm::MachO::MH_DSYM:
+        // We don't generate load commands for these file types, even if
+        // forced on.
+        break;
+    }
+  }
+
+  // Handle -function_starts or -no_function_starts
+  {
+    bool flagOn = false;
+    bool flagOff = false;
+    if (auto *arg = parsedArgs.getLastArg(OPT_function_starts,
+                                          OPT_no_function_starts)) {
+      flagOn = arg->getOption().getID() == OPT_function_starts;
+      flagOff = arg->getOption().getID() == OPT_no_function_starts;
+    }
+
+    // default to adding functions start for dynamic code, static code must
+    // opt-in
+    switch (ctx.outputMachOType()) {
+      case llvm::MachO::MH_OBJECT:
+        ctx.setGenerateFunctionStartsLoadCommand(false);
+        break;
+      case llvm::MachO::MH_EXECUTE:
+        // dynamic executables default to generating a version load command,
+        // while static exectuables only generate it if required.
+        if (isStaticExecutable) {
+          if (flagOn)
+            ctx.setGenerateFunctionStartsLoadCommand(true);
+        } else {
+          if (!flagOff)
+            ctx.setGenerateFunctionStartsLoadCommand(true);
+        }
+        break;
+      case llvm::MachO::MH_PRELOAD:
+      case llvm::MachO::MH_KEXT_BUNDLE:
+        if (flagOn)
+          ctx.setGenerateFunctionStartsLoadCommand(true);
+        break;
+      case llvm::MachO::MH_DYLINKER:
+      case llvm::MachO::MH_DYLIB:
+      case llvm::MachO::MH_BUNDLE:
+        if (!flagOff)
+          ctx.setGenerateFunctionStartsLoadCommand(true);
+        break;
+      case llvm::MachO::MH_FVMLIB:
+      case llvm::MachO::MH_DYLDLINK:
+      case llvm::MachO::MH_DYLIB_STUB:
+      case llvm::MachO::MH_DSYM:
+        // We don't generate load commands for these file types, even if
+        // forced on.
+        break;
+    }
+  }
+
+  // Handle -data_in_code_info or -no_data_in_code_info
+  {
+    bool flagOn = false;
+    bool flagOff = false;
+    if (auto *arg = parsedArgs.getLastArg(OPT_data_in_code_info,
+                                          OPT_no_data_in_code_info)) {
+      flagOn = arg->getOption().getID() == OPT_data_in_code_info;
+      flagOff = arg->getOption().getID() == OPT_no_data_in_code_info;
+    }
+
+    // default to adding data in code for dynamic code, static code must
+    // opt-in
+    switch (ctx.outputMachOType()) {
+      case llvm::MachO::MH_OBJECT:
+        if (!flagOff)
+          ctx.setGenerateDataInCodeLoadCommand(true);
+        break;
+      case llvm::MachO::MH_EXECUTE:
+        // dynamic executables default to generating a version load command,
+        // while static exectuables only generate it if required.
+        if (isStaticExecutable) {
+          if (flagOn)
+            ctx.setGenerateDataInCodeLoadCommand(true);
+        } else {
+          if (!flagOff)
+            ctx.setGenerateDataInCodeLoadCommand(true);
+        }
+        break;
+      case llvm::MachO::MH_PRELOAD:
+      case llvm::MachO::MH_KEXT_BUNDLE:
+        if (flagOn)
+          ctx.setGenerateDataInCodeLoadCommand(true);
+        break;
+      case llvm::MachO::MH_DYLINKER:
+      case llvm::MachO::MH_DYLIB:
+      case llvm::MachO::MH_BUNDLE:
+        if (!flagOff)
+          ctx.setGenerateDataInCodeLoadCommand(true);
+        break;
+      case llvm::MachO::MH_FVMLIB:
+      case llvm::MachO::MH_DYLDLINK:
+      case llvm::MachO::MH_DYLIB_STUB:
+      case llvm::MachO::MH_DSYM:
+        // We don't generate load commands for these file types, even if
+        // forced on.
+        break;
+    }
+  }
+
+  // Handle sdk_version
+  if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_sdk_version)) {
+    uint32_t sdkVersion = 0;
+    if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
+                                                sdkVersion)) {
+      diagnostics << "error: malformed sdkVersion value\n";
+      return false;
+    }
+    ctx.setSdkVersion(sdkVersion);
+  } else if (ctx.generateVersionLoadCommand()) {
+    // If we don't have an sdk version, but were going to emit a load command
+    // with min_version, then we need to give an warning as we have no sdk
+    // version to put in that command.
+    // FIXME: We need to decide whether to make this an error.
+    diagnostics << "warning: -sdk_version is required when emitting "
+                   "min version load command.  "
+                   "Setting sdk version to match provided min version\n";
+    ctx.setSdkVersion(ctx.osMinVersion());
+  }
+
+  // Handle source_version
+  if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_source_version)) {
+    uint64_t version = 0;
+    if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
+                                                version)) {
+      diagnostics << "error: malformed source_version value\n";
+      return false;
+    }
+    ctx.setSourceVersion(version);
+  }
+
+  // Handle stack_size
+  if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) {
+    uint64_t stackSizeVal;
+    if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) {
+      diagnostics << "error: stack_size expects a hex number\n";
+      return false;
+    }
+    if ((stackSizeVal % ctx.pageSize()) != 0) {
+      diagnostics << "error: stack_size must be a multiple of page size ("
+                  << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
+      return false;
+    }
+
+    ctx.setStackSize(stackSizeVal);
+  }
+
+  // Handle debug info handling options: -S
+  if (parsedArgs.hasArg(OPT_S))
+    ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap);
+
+  // Handle -order_file <file>
+  for (auto orderFile : parsedArgs.filtered(OPT_order_file)) {
+    if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx,
+                                              diagnostics)) {
+      diagnostics << "error: " << ec.message()
+                  << ", processing '-order_file "
+                  << orderFile->getValue()
+                  << "'\n";
+      return false;
+    }
+  }
+
+  // Handle -flat_namespace.
+  if (llvm::opt::Arg *ns =
+          parsedArgs.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) {
+    if (ns->getOption().getID() == OPT_flat_namespace)
+      ctx.setUseFlatNamespace(true);
+  }
+
+  // Handle -undefined
+  if (llvm::opt::Arg *undef = parsedArgs.getLastArg(OPT_undefined)) {
+    MachOLinkingContext::UndefinedMode UndefMode;
+    if (StringRef(undef->getValue()).equals("error"))
+      UndefMode = MachOLinkingContext::UndefinedMode::error;
+    else if (StringRef(undef->getValue()).equals("warning"))
+      UndefMode = MachOLinkingContext::UndefinedMode::warning;
+    else if (StringRef(undef->getValue()).equals("suppress"))
+      UndefMode = MachOLinkingContext::UndefinedMode::suppress;
+    else if (StringRef(undef->getValue()).equals("dynamic_lookup"))
+      UndefMode = MachOLinkingContext::UndefinedMode::dynamicLookup;
+    else {
+      diagnostics << "error: invalid option to -undefined "
+                     "[ warning | error | suppress | dynamic_lookup ]\n";
+      return false;
+    }
+
+    if (ctx.useFlatNamespace()) {
+      // If we're using -flat_namespace then 'warning', 'suppress' and
+      // 'dynamic_lookup' are all equivalent, so map them to 'suppress'.
+      if (UndefMode != MachOLinkingContext::UndefinedMode::error)
+        UndefMode = MachOLinkingContext::UndefinedMode::suppress;
+    } else {
+      // If we're using -twolevel_namespace then 'warning' and 'suppress' are
+      // illegal. Emit a diagnostic if they've been (mis)used.
+      if (UndefMode == MachOLinkingContext::UndefinedMode::warning ||
+          UndefMode == MachOLinkingContext::UndefinedMode::suppress) {
+        diagnostics << "error: can't use -undefined warning or suppress with "
+                       "-twolevel_namespace\n";
+        return false;
+      }
+    }
+
+    ctx.setUndefinedMode(UndefMode);
+  }
+
+  // Handle -no_objc_category_merging.
+  if (parsedArgs.getLastArg(OPT_no_objc_category_merging))
+    ctx.setMergeObjCCategories(false);
+
+  // Handle -rpath <path>
+  if (parsedArgs.hasArg(OPT_rpath)) {
+    switch (ctx.outputMachOType()) {
+      case llvm::MachO::MH_EXECUTE:
+      case llvm::MachO::MH_DYLIB:
+      case llvm::MachO::MH_BUNDLE:
+        if (!ctx.minOS("10.5", "2.0")) {
+          if (ctx.os() == MachOLinkingContext::OS::macOSX) {
+            diagnostics << "error: -rpath can only be used when targeting "
+                           "OS X 10.5 or later\n";
+          } else {
+            diagnostics << "error: -rpath can only be used when targeting "
+                           "iOS 2.0 or later\n";
+          }
+          return false;
+        }
+        break;
+      default:
+        diagnostics << "error: -rpath can only be used when creating "
+                       "a dynamic final linked image\n";
+        return false;
+    }
+
+    for (auto rPath : parsedArgs.filtered(OPT_rpath)) {
+      ctx.addRpath(rPath->getValue());
+    }
+  }
+
+  // Parse the LLVM options before we process files in case the file handling
+  // makes use of things like DEBUG().
+  parseLLVMOptions(ctx);
+
+  // Handle input files and sectcreate.
+  for (auto &arg : parsedArgs) {
+    bool upward;
+    llvm::Optional<StringRef> resolvedPath;
+    switch (arg->getOption().getID()) {
+    default:
+      continue;
+    case OPT_INPUT:
+      addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics);
+      break;
+    case OPT_upward_library:
+      addFile(arg->getValue(), ctx, false, true, diagnostics);
+      break;
+    case OPT_force_load:
+      addFile(arg->getValue(), ctx, true, false, diagnostics);
+      break;
+    case OPT_l:
+    case OPT_upward_l:
+      upward = (arg->getOption().getID() == OPT_upward_l);
+      resolvedPath = ctx.searchLibrary(arg->getValue());
+      if (!resolvedPath) {
+        diagnostics << "Unable to find library for " << arg->getSpelling()
+                    << arg->getValue() << "\n";
+        return false;
+      } else if (ctx.testingFileUsage()) {
+        diagnostics << "Found " << (upward ? "upward " : " ") << "library "
+                   << canonicalizePath(resolvedPath.getValue()) << '\n';
+      }
+      addFile(resolvedPath.getValue(), ctx, globalWholeArchive,
+              upward, diagnostics);
+      break;
+    case OPT_framework:
+    case OPT_upward_framework:
+      upward = (arg->getOption().getID() == OPT_upward_framework);
+      resolvedPath = ctx.findPathForFramework(arg->getValue());
+      if (!resolvedPath) {
+        diagnostics << "Unable to find framework for "
+                    << arg->getSpelling() << " " << arg->getValue() << "\n";
+        return false;
+      } else if (ctx.testingFileUsage()) {
+        diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
+                    << canonicalizePath(resolvedPath.getValue()) << '\n';
+      }
+      addFile(resolvedPath.getValue(), ctx, globalWholeArchive,
+              upward, diagnostics);
+      break;
+    case OPT_filelist:
+      if (auto ec = loadFileList(arg->getValue(),
+                                 ctx, globalWholeArchive,
+                                 diagnostics)) {
+        handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) {
+          diagnostics << "error: ";
+          EI.log(diagnostics);
+          diagnostics << ", processing '-filelist " << arg->getValue() << "'\n";
+        });
+        return false;
+      }
+      break;
+    case OPT_sectcreate: {
+        const char* seg  = arg->getValue(0);
+        const char* sect = arg->getValue(1);
+        const char* fileName = arg->getValue(2);
+
+        ErrorOr<std::unique_ptr<MemoryBuffer>> contentOrErr =
+          MemoryBuffer::getFile(fileName);
+
+        if (!contentOrErr) {
+          diagnostics << "error: can't open -sectcreate file " << fileName << "\n";
+          return false;
+        }
+
+        ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr));
+      }
+      break;
+    }
+  }
+
+  if (ctx.getNodes().empty()) {
+    diagnostics << "No input files\n";
+    return false;
+  }
+
+  // Validate the combination of options used.
+  return ctx.validate(diagnostics);
+}
+
+static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
+  std::vector<std::unique_ptr<File>> Files;
+  if (Implicit)
+    ctx.createImplicitFiles(Files);
+  else
+    ctx.createInternalFiles(Files);
+  for (auto i = Files.rbegin(), e = Files.rend(); i != e; ++i) {
+    auto &members = ctx.getNodes();
+    members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+  }
+}
+
+/// This is where the link is actually performed.
+bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
+  MachOLinkingContext ctx;
+  if (!parse(args, ctx, diagnostics))
+    return false;
+  if (ctx.doNothing())
+    return true;
+  if (ctx.getNodes().empty())
+    return false;
+
+  for (std::unique_ptr<Node> &ie : ctx.getNodes())
+    if (FileNode *node = dyn_cast<FileNode>(ie.get()))
+      node->getFile()->parse();
+
+  createFiles(ctx, false /* Implicit */);
+
+  // Give target a chance to add files
+  createFiles(ctx, true /* Implicit */);
+
+  // Give target a chance to postprocess input files.
+  // Mach-O uses this chance to move all object files before library files.
+  ctx.finalizeInputFiles();
+
+  // Do core linking.
+  ScopedTask resolveTask(getDefaultDomain(), "Resolve");
+  Resolver resolver(ctx);
+  if (!resolver.resolve())
+    return false;
+  SimpleFile *merged = nullptr;
+  {
+    std::unique_ptr<SimpleFile> mergedFile = resolver.resultFile();
+    merged = mergedFile.get();
+    auto &members = ctx.getNodes();
+    members.insert(members.begin(),
+                   llvm::make_unique<FileNode>(std::move(mergedFile)));
+  }
+  resolveTask.end();
+
+  // Run passes on linked atoms.
+  ScopedTask passTask(getDefaultDomain(), "Passes");
+  PassManager pm;
+  ctx.addPasses(pm);
+  if (auto ec = pm.runOnFile(*merged)) {
+    // FIXME: This should be passed to logAllUnhandledErrors but it needs
+    // to be passed a Twine instead of a string.
+    diagnostics << "Failed to run passes on file '" << ctx.outputPath()
+                << "': ";
+    logAllUnhandledErrors(std::move(ec), diagnostics, std::string());
+    return false;
+  }
+
+  passTask.end();
+
+  // Give linked atoms to Writer to generate output file.
+  ScopedTask writeTask(getDefaultDomain(), "Write");
+  if (auto ec = ctx.writeFile(*merged)) {
+    // FIXME: This should be passed to logAllUnhandledErrors but it needs
+    // to be passed a Twine instead of a string.
+    diagnostics << "Failed to write file '" << ctx.outputPath() << "': ";
+    logAllUnhandledErrors(std::move(ec), diagnostics, std::string());
+    return false;
+  }
+
+  return true;
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
new file mode 100644 (file)
index 0000000..fa07f33
--- /dev/null
@@ -0,0 +1,242 @@
+include "llvm/Option/OptParser.td"
+
+
+// output kinds
+def grp_kind : OptionGroup<"outs">, HelpText<"OUTPUT KIND">;
+def relocatable : Flag<["-"], "r">,
+     HelpText<"Create relocatable object file">, Group<grp_kind>;
+def static : Flag<["-"], "static">,
+     HelpText<"Create static executable">, Group<grp_kind>;
+def dynamic : Flag<["-"], "dynamic">,
+     HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
+def dylib : Flag<["-"], "dylib">,
+     HelpText<"Create dynamic library">, Group<grp_kind>;
+def bundle : Flag<["-"], "bundle">,
+     HelpText<"Create dynamic bundle">, Group<grp_kind>;
+def execute : Flag<["-"], "execute">,
+     HelpText<"Create main executable (default)">, Group<grp_kind>;
+def preload : Flag<["-"], "preload">,
+     HelpText<"Create binary for use with embedded systems">, Group<grp_kind>;
+
+// optimizations
+def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">;
+def dead_strip : Flag<["-"], "dead_strip">,
+     HelpText<"Remove unreference code and data">, Group<grp_opts>;
+def macosx_version_min : Separate<["-"], "macosx_version_min">,
+     MetaVarName<"<version>">,
+     HelpText<"Minimum Mac OS X version">, Group<grp_opts>;
+def ios_version_min : Separate<["-"], "ios_version_min">,
+     MetaVarName<"<version>">,
+     HelpText<"Minimum iOS version">, Group<grp_opts>;
+def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">,
+     Alias<ios_version_min>;
+def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
+     MetaVarName<"<version>">,
+     HelpText<"Minimum iOS simulator version">, Group<grp_opts>;
+def sdk_version : Separate<["-"], "sdk_version">,
+     MetaVarName<"<version>">,
+     HelpText<"SDK version">, Group<grp_opts>;
+def source_version : Separate<["-"], "source_version">,
+     MetaVarName<"<version>">,
+     HelpText<"Source version">, Group<grp_opts>;
+def version_load_command : Flag<["-"], "version_load_command">,
+     HelpText<"Force generation of a version load command">, Group<grp_opts>;
+def no_version_load_command : Flag<["-"], "no_version_load_command">,
+     HelpText<"Disable generation of a version load command">, Group<grp_opts>;
+def function_starts : Flag<["-"], "function_starts">,
+     HelpText<"Force generation of a function starts load command">,
+     Group<grp_opts>;
+def no_function_starts : Flag<["-"], "no_function_starts">,
+     HelpText<"Disable generation of a function starts load command">,
+     Group<grp_opts>;
+def data_in_code_info : Flag<["-"], "data_in_code_info">,
+     HelpText<"Force generation of a data in code load command">,
+     Group<grp_opts>;
+def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">,
+     HelpText<"Disable generation of a data in code load command">,
+     Group<grp_opts>;
+def mllvm : Separate<["-"], "mllvm">,
+     MetaVarName<"<option>">,
+     HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
+def exported_symbols_list : Separate<["-"], "exported_symbols_list">,
+     MetaVarName<"<file-path>">,
+     HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def exported_symbol : Separate<["-"], "exported_symbol">,
+     MetaVarName<"<symbol>">,
+     HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def unexported_symbols_list : Separate<["-"], "unexported_symbols_list">,
+     MetaVarName<"<file-path>">,
+     HelpText<"Lists symbols that should not be exported">, Group<grp_opts>;
+def unexported_symbol : Separate<["-"], "unexported_symbol">,
+     MetaVarName<"<symbol>">,
+     HelpText<"A symbol which should not be exported">, Group<grp_opts>;
+def keep_private_externs : Flag<["-"], "keep_private_externs">,
+     HelpText<"Private extern (hidden) symbols should not be transformed "
+              "into local symbols">, Group<grp_opts>;
+def order_file : Separate<["-"], "order_file">,
+     MetaVarName<"<file-path>">,
+     HelpText<"re-order and move specified symbols to start of their section">,
+     Group<grp_opts>;
+def flat_namespace : Flag<["-"], "flat_namespace">,
+     HelpText<"Resolves symbols in any (transitively) linked dynamic libraries. "
+              "Source libraries are not recorded: dyld will re-search all "
+              "images at runtime and use the first definition found.">,
+     Group<grp_opts>;
+def twolevel_namespace : Flag<["-"], "twolevel_namespace">,
+     HelpText<"Resolves symbols in listed libraries only. Source libraries are "
+              "recorded in the symbol table.">,
+     Group<grp_opts>;
+def undefined : Separate<["-"], "undefined">,
+                MetaVarName<"<undefined>">,
+                HelpText<"Determines how undefined symbols are handled.">,
+                Group<grp_opts>;
+def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">,
+     HelpText<"Disables the optimisation which merges Objective-C categories "
+              "on a class in to the class itself.">,
+     Group<grp_opts>;
+
+// main executable options
+def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
+def entry : Separate<["-"], "e">,
+     MetaVarName<"<entry-name>">,
+     HelpText<"entry symbol name">,Group<grp_main>;
+def pie : Flag<["-"], "pie">,
+     HelpText<"Create Position Independent Executable (for ASLR)">,
+     Group<grp_main>;
+def no_pie : Flag<["-"], "no_pie">,
+     HelpText<"Do not create Position Independent Executable">,
+     Group<grp_main>;
+def stack_size : Separate<["-"], "stack_size">,
+     HelpText<"Specifies the maximum stack size for the main thread in a program. "
+              "Must be a page-size multiple. (default=8Mb)">,
+     Group<grp_main>;
+def export_dynamic : Flag<["-"], "export_dynamic">,
+     HelpText<"Preserves all global symbols in main executables during LTO">,
+     Group<grp_main>;
+
+// dylib executable options
+def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
+def install_name : Separate<["-"], "install_name">,
+     MetaVarName<"<path>">,
+     HelpText<"The dylib's install name">, Group<grp_dylib>;
+def mark_dead_strippable_dylib : Flag<["-"], "mark_dead_strippable_dylib">,
+     HelpText<"Marks the dylib as having no side effects during initialization">,
+     Group<grp_dylib>;
+def compatibility_version : Separate<["-"], "compatibility_version">,
+     MetaVarName<"<version>">,
+     HelpText<"The dylib's compatibility version">, Group<grp_dylib>;
+def current_version : Separate<["-"], "current_version">,
+     MetaVarName<"<version>">,
+     HelpText<"The dylib's current version">, Group<grp_dylib>;
+
+// dylib executable options - compatibility aliases
+def dylib_install_name : Separate<["-"], "dylib_install_name">,
+     Alias<install_name>;
+def dylib_compatibility_version : Separate<["-"], "dylib_compatibility_version">,
+     MetaVarName<"<version>">, Alias<compatibility_version>;
+def dylib_current_version : Separate<["-"], "dylib_current_version">,
+     MetaVarName<"<version>">, Alias<current_version>;
+
+// bundle executable options
+def grp_bundle : OptionGroup<"opts">, HelpText<"BUNDLE EXECUTABLE OPTIONS">;
+def bundle_loader : Separate<["-"], "bundle_loader">,
+     MetaVarName<"<path>">,
+     HelpText<"The executable that will be loading this Mach-O bundle">,
+     Group<grp_bundle>;
+
+// library options
+def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">;
+def L : JoinedOrSeparate<["-"], "L">,
+     MetaVarName<"<dir>">,
+     HelpText<"Add directory to library search path">, Group<grp_libs>;
+def F : JoinedOrSeparate<["-"], "F">,
+     MetaVarName<"<dir>">,
+     HelpText<"Add directory to framework search path">, Group<grp_libs>;
+def Z : Flag<["-"], "Z">,
+     HelpText<"Do not search standard directories for libraries or frameworks">;
+def all_load : Flag<["-"], "all_load">,
+     HelpText<"Forces all members of all static libraries to be loaded">,
+     Group<grp_libs>;
+def force_load : Separate<["-"], "force_load">,
+     MetaVarName<"<library-path>">,
+     HelpText<"Forces all members of specified static libraries to be loaded">,
+     Group<grp_libs>;
+def syslibroot : Separate<["-"], "syslibroot">, MetaVarName<"<dir>">,
+     HelpText<"Add path to SDK to all absolute library search paths">,
+     Group<grp_libs>;
+
+// Input options
+def l : Joined<["-"], "l">,
+     MetaVarName<"<libname>">,
+     HelpText<"Base name of library searched for in -L directories">;
+def upward_l : Joined<["-"], "upward-l">,
+     MetaVarName<"<libname>">,
+     HelpText<"Base name of upward library searched for in -L directories">;
+def framework : Separate<["-"], "framework">,
+     MetaVarName<"<name>">,
+     HelpText<"Base name of framework searched for in -F directories">;
+def upward_framework : Separate<["-"], "upward_framework">,
+     MetaVarName<"<name>">,
+     HelpText<"Base name of upward framework searched for in -F directories">;
+def upward_library : Separate<["-"], "upward_library">,
+     MetaVarName<"<path>">,
+     HelpText<"path to upward dylib to link with">;
+def filelist : Separate<["-"], "filelist">,
+     MetaVarName<"<path>">,
+     HelpText<"file containing paths to input files">;
+
+
+// test case options
+def print_atoms : Flag<["-"], "print_atoms">,
+     HelpText<"Emit output as yaml atoms">;
+def test_file_usage : Flag<["-"], "test_file_usage">,
+     HelpText<"Only files specified by -file_exists are considered to exist. "
+              "Print which files would be used">;
+def path_exists : Separate<["-"], "path_exists">,
+     MetaVarName<"<path>">,
+     HelpText<"Used with -test_file_usage to declare a path">;
+
+
+// general options
+def output : Separate<["-"], "o">,
+     MetaVarName<"<path>">,
+     HelpText<"Output file path">;
+def arch : Separate<["-"], "arch">,
+     MetaVarName<"<arch-name>">,
+     HelpText<"Architecture to link">;
+def sectalign : MultiArg<["-"], "sectalign", 3>,
+     MetaVarName<"<segname> <sectname> <alignment>">,
+     HelpText<"Alignment for segment/section">;
+def sectcreate : MultiArg<["-"], "sectcreate", 3>,
+     MetaVarName<"<segname> <sectname> <file>">,
+     HelpText<"Create section <segname>/<sectname> from contents of <file>">;
+def image_base : Separate<["-"], "image_base">;
+def seg1addr : Separate<["-"], "seg1addr">, Alias<image_base>;
+def demangle : Flag<["-"], "demangle">,
+     HelpText<"Demangles symbol names in errors and warnings">;
+def dependency_info : Separate<["-"], "dependency_info">,
+     MetaVarName<"<file>">,
+     HelpText<"Write binary list of files used during link">;
+def S : Flag<["-"], "S">,
+     HelpText<"Remove debug information (STABS or DWARF) from the output file">;
+def rpath : Separate<["-"], "rpath">,
+     MetaVarName<"<path>">,
+     HelpText<"Add path to the runpath search path list for image being created">;
+
+def t : Flag<["-"], "t">,
+     HelpText<"Print the names of the input files as ld processes them">;
+def v : Flag<["-"], "v">,
+     HelpText<"Print linker information">;
+
+// Obsolete options
+def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">;
+def single_module : Flag<["-"], "single_module">,
+     HelpText<"Default for dylibs">, Group<grp_obsolete>;
+def multi_module : Flag<["-"], "multi_module">,
+     HelpText<"Unsupported way to build dylibs">, Group<grp_obsolete>;
+def objc_gc_compaction : Flag<["-"], "objc_gc_compaction">,
+     HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc : Flag<["-"], "objc_gc">,
+     HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc_only : Flag<["-"], "objc_gc_only">,
+     HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
diff --git a/lib/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8751d56
--- /dev/null
@@ -0,0 +1,21 @@
+add_subdirectory(MachO)
+add_subdirectory(YAML)
+
+if (MSVC)
+  add_definitions(-wd4062) # Suppress 'warning C4062: Enumerator has no associated handler in a switch statement.'
+endif()
+
+add_lld_library(lldReaderWriter
+  FileArchive.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLD_INCLUDE_DIR}/lld/ReaderWriter
+
+  LINK_COMPONENTS
+    Object
+    Support
+
+  LINK_LIBS
+    lldCore
+    lldYAML
+  )
diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp
new file mode 100644 (file)
index 0000000..762d087
--- /dev/null
@@ -0,0 +1,228 @@
+//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <set>
+#include <string>
+#include <system_error>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+using llvm::object::Archive;
+using llvm::file_magic;
+using llvm::identify_magic;
+
+namespace lld {
+
+namespace {
+
+/// \brief The FileArchive class represents an Archive Library file
+class FileArchive : public lld::ArchiveLibraryFile {
+public:
+  FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
+              StringRef path, bool logLoading)
+      : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
+        _registry(reg), _logLoading(logLoading) {}
+
+  /// \brief Check if any member of the archive contains an Atom with the
+  /// specified name and return the File object for that member, or nullptr.
+  File *find(StringRef name) override {
+    auto member = _symbolMemberMap.find(name);
+    if (member == _symbolMemberMap.end())
+      return nullptr;
+    Archive::Child c = member->second;
+
+    // Don't return a member already returned
+    Expected<StringRef> buf = c.getBuffer();
+    if (!buf) {
+      // TODO: Actually report errors helpfully.
+      consumeError(buf.takeError());
+      return nullptr;
+    }
+    const char *memberStart = buf->data();
+    if (_membersInstantiated.count(memberStart))
+      return nullptr;
+    _membersInstantiated.insert(memberStart);
+
+    std::unique_ptr<File> result;
+    if (instantiateMember(c, result))
+      return nullptr;
+
+    File *file = result.get();
+    _filesReturned.push_back(std::move(result));
+
+    // Give up the file pointer. It was stored and will be destroyed with destruction of FileArchive
+    return file;
+  }
+
+  /// \brief parse each member
+  std::error_code
+  parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+    if (std::error_code ec = parse())
+      return ec;
+    llvm::Error err = llvm::Error::success();
+    for (auto mf = _archive->child_begin(err), me = _archive->child_end();
+         mf != me; ++mf) {
+      std::unique_ptr<File> file;
+      if (std::error_code ec = instantiateMember(*mf, file)) {
+        // err is Success (or we wouldn't be in the loop body) but we can't
+        // return without testing or consuming it.
+        consumeError(std::move(err));
+        return ec;
+      }
+      result.push_back(std::move(file));
+    }
+    if (err)
+      return errorToErrorCode(std::move(err));
+    return std::error_code();
+  }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _noDefinedAtoms;
+  }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _noDefinedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+
+protected:
+  std::error_code doParse() override {
+    // Make Archive object which will be owned by FileArchive object.
+    llvm::Error Err = llvm::Error::success();
+    _archive.reset(new Archive(_mb->getMemBufferRef(), Err));
+    if (Err)
+      return errorToErrorCode(std::move(Err));
+    std::error_code ec;
+    if ((ec = buildTableOfContents()))
+      return ec;
+    return std::error_code();
+  }
+
+private:
+  std::error_code instantiateMember(Archive::Child member,
+                                    std::unique_ptr<File> &result) const {
+    Expected<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef();
+    if (!mbOrErr)
+      return errorToErrorCode(mbOrErr.takeError());
+    llvm::MemoryBufferRef mb = mbOrErr.get();
+    std::string memberPath = (_archive->getFileName() + "("
+                           + mb.getBufferIdentifier() + ")").str();
+
+    if (_logLoading)
+      llvm::errs() << memberPath << "\n";
+
+    std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
+        mb.getBuffer(), mb.getBufferIdentifier(), false));
+
+    ErrorOr<std::unique_ptr<File>> fileOrErr =
+        _registry.loadFile(std::move(memberMB));
+    if (std::error_code ec = fileOrErr.getError())
+      return ec;
+    result = std::move(fileOrErr.get());
+    if (std::error_code ec = result->parse())
+      return ec;
+    result->setArchivePath(_archive->getFileName());
+
+    // The memory buffer is co-owned by the archive file and the children,
+    // so that the bufffer is deallocated when all the members are destructed.
+    result->setSharedMemoryBuffer(_mb);
+    return std::error_code();
+  }
+
+  std::error_code buildTableOfContents() {
+    DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
+                                       << "Table of contents for archive '"
+                                       << _archive->getFileName() << "':\n");
+    for (const Archive::Symbol &sym : _archive->symbols()) {
+      StringRef name = sym.getName();
+      Expected<Archive::Child> memberOrErr = sym.getMember();
+      if (!memberOrErr)
+        return errorToErrorCode(memberOrErr.takeError());
+      Archive::Child member = memberOrErr.get();
+      DEBUG_WITH_TYPE("FileArchive",
+                      llvm::dbgs()
+                          << llvm::format("0x%08llX ",
+                                          member.getBuffer()->data())
+                          << "'" << name << "'\n");
+      _symbolMemberMap.insert(std::make_pair(name, member));
+    }
+    return std::error_code();
+  }
+
+  typedef std::unordered_map<StringRef, Archive::Child> MemberMap;
+  typedef std::set<const char *> InstantiatedSet;
+
+  std::shared_ptr<MemoryBuffer> _mb;
+  const Registry &_registry;
+  std::unique_ptr<Archive> _archive;
+  MemberMap _symbolMemberMap;
+  InstantiatedSet _membersInstantiated;
+  bool _logLoading;
+  std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
+  std::vector<std::unique_ptr<File>> _filesReturned;
+};
+
+class ArchiveReader : public Reader {
+public:
+  ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef) const override {
+    return magic == file_magic::archive;
+  }
+
+  ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
+                                          const Registry &reg) const override {
+    StringRef path = mb->getBufferIdentifier();
+    std::unique_ptr<File> ret =
+        llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
+    return std::move(ret);
+  }
+
+private:
+  bool _logLoading;
+};
+
+} // anonymous namespace
+
+void Registry::addSupportArchives(bool logLoading) {
+  add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
+}
+
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler.cpp b/lib/ReaderWriter/MachO/ArchHandler.cpp
new file mode 100644 (file)
index 0000000..cb20907
--- /dev/null
@@ -0,0 +1,172 @@
+//===- lib/FileFormat/MachO/ArchHandler.cpp -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+
+ArchHandler::ArchHandler() {
+}
+
+ArchHandler::~ArchHandler() {
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create(
+                                               MachOLinkingContext::Arch arch) {
+  switch (arch) {
+  case MachOLinkingContext::arch_x86_64:
+    return create_x86_64();
+  case MachOLinkingContext::arch_x86:
+    return create_x86();
+  case MachOLinkingContext::arch_armv6:
+  case MachOLinkingContext::arch_armv7:
+  case MachOLinkingContext::arch_armv7s:
+    return create_arm();
+  case MachOLinkingContext::arch_arm64:
+    return create_arm64();
+  default:
+    llvm_unreachable("Unknown arch");
+  }
+}
+
+
+bool ArchHandler::isLazyPointer(const Reference &ref) {
+  // A lazy bind entry is needed for a lazy pointer.
+  const StubInfo &info = stubInfo();
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch)
+    return false;
+  return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind);
+}
+
+
+ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) {
+  assert((reloc.type & 0xFFF0) == 0);
+  uint16_t result = reloc.type;
+  if (reloc.scattered)
+    result |= rScattered;
+  if (reloc.pcRel)
+    result |= rPcRel;
+  if (reloc.isExtern)
+    result |= rExtern;
+  switch(reloc.length) {
+  case 0:
+    break;
+  case 1:
+    result |= rLength2;
+    break;
+  case 2:
+    result |= rLength4;
+    break;
+  case 3:
+    result |= rLength8;
+    break;
+  default:
+    llvm_unreachable("bad r_length");
+  }
+  return result;
+}
+
+normalized::Relocation
+ArchHandler::relocFromPattern(ArchHandler::RelocPattern pattern) {
+  normalized::Relocation result;
+  result.offset    = 0;
+  result.scattered = (pattern & rScattered);
+  result.type     = (RelocationInfoType)(pattern & 0xF);
+  result.pcRel    = (pattern & rPcRel);
+  result.isExtern = (pattern & rExtern);
+  result.value    = 0;
+  result.symbol    = 0;
+  switch (pattern & 0x300) {
+  case rLength1:
+    result.length = 0;
+    break;
+  case rLength2:
+    result.length = 1;
+    break;
+  case rLength4:
+    result.length = 2;
+    break;
+  case rLength8:
+    result.length = 3;
+    break;
+  }
+  return result;
+}
+
+void ArchHandler::appendReloc(normalized::Relocations &relocs, uint32_t offset,
+                              uint32_t symbol, uint32_t value,
+                              RelocPattern pattern) {
+  normalized::Relocation reloc = relocFromPattern(pattern);
+  reloc.offset = offset;
+  reloc.symbol = symbol;
+  reloc.value  = value;
+  relocs.push_back(reloc);
+}
+
+
+int16_t ArchHandler::readS16(const uint8_t *addr, bool isBig) {
+    return read16(addr, isBig);
+}
+
+int32_t ArchHandler::readS32(const uint8_t *addr, bool isBig) {
+  return read32(addr, isBig);
+}
+
+uint32_t ArchHandler::readU32(const uint8_t *addr, bool isBig) {
+  return read32(addr, isBig);
+}
+
+  int64_t ArchHandler::readS64(const uint8_t *addr, bool isBig) {
+  return read64(addr, isBig);
+}
+
+bool ArchHandler::isDwarfCIE(bool isBig, const DefinedAtom *atom) {
+  assert(atom->contentType() == DefinedAtom::typeCFI);
+  if (atom->rawContent().size() < sizeof(uint32_t))
+    return false;
+  uint32_t size = read32(atom->rawContent().data(), isBig);
+
+  uint32_t idOffset = sizeof(uint32_t);
+  if (size == 0xffffffffU)
+    idOffset += sizeof(uint64_t);
+
+  return read32(atom->rawContent().data() + idOffset, isBig) == 0;
+}
+
+const Atom *ArchHandler::fdeTargetFunction(const DefinedAtom *fde) {
+  for (auto ref : *fde) {
+    if (ref->kindNamespace() == Reference::KindNamespace::mach_o &&
+        ref->kindValue() == unwindRefToFunctionKind()) {
+      assert(ref->kindArch() == kindArch() && "unexpected Reference arch");
+      return ref->target();
+    }
+  }
+
+  return nullptr;
+}
+
+} // namespace mach_o
+} // namespace lld
+
+
+
diff --git a/lib/ReaderWriter/MachO/ArchHandler.h b/lib/ReaderWriter/MachO/ArchHandler.h
new file mode 100644 (file)
index 0000000..70a63bd
--- /dev/null
@@ -0,0 +1,319 @@
+//===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// The ArchHandler class handles all architecture specific aspects of
+/// mach-o linking.
+///
+class ArchHandler {
+public:
+  virtual ~ArchHandler();
+
+  /// There is no public interface to subclasses of ArchHandler, so this
+  /// is the only way to instantiate an ArchHandler.
+  static std::unique_ptr<ArchHandler> create(MachOLinkingContext::Arch arch);
+
+  /// Get (arch specific) kind strings used by Registry.
+  virtual const Registry::KindStrings *kindStrings() = 0;
+
+  /// Convert mach-o Arch to Reference::KindArch.
+  virtual Reference::KindArch kindArch() = 0;
+
+  /// Used by StubPass to update References to shared library functions
+  /// to be references to a stub.
+  virtual bool isCallSite(const Reference &) = 0;
+
+  /// Used by GOTPass to locate GOT References
+  virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) {
+    return false;
+  }
+
+  /// Used by TLVPass to locate TLV References.
+  virtual bool isTLVAccess(const Reference &) const { return false; }
+
+  /// Used by the TLVPass to update TLV References.
+  virtual void updateReferenceToTLV(const Reference *) {}
+
+  /// Used by ShimPass to insert shims in branches that switch mode.
+  virtual bool isNonCallBranch(const Reference &) = 0;
+
+  /// Used by GOTPass to update GOT References
+  virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {}
+
+  /// Does this architecture make use of __unwind_info sections for exception
+  /// handling? If so, it will need a separate pass to create them.
+  virtual bool needsCompactUnwind() = 0;
+
+  /// Returns the kind of reference to use to synthesize a 32-bit image-offset
+  /// value, used in the __unwind_info section.
+  virtual Reference::KindValue imageOffsetKind() = 0;
+
+  /// Returns the kind of reference to use to synthesize a 32-bit image-offset
+  /// indirect value. Used for personality functions in the __unwind_info
+  /// section.
+  virtual Reference::KindValue imageOffsetKindIndirect() = 0;
+
+  /// Architecture specific compact unwind type that signals __eh_frame should
+  /// actually be used.
+  virtual uint32_t dwarfCompactUnwindType() = 0;
+
+  /// Reference from an __eh_frame CIE atom to its personality function it's
+  /// describing. Usually pointer-sized and PC-relative, but differs in whether
+  /// it needs to be in relocatable objects.
+  virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0;
+
+  /// Reference from an __eh_frame FDE to the CIE it's based on.
+  virtual Reference::KindValue unwindRefToCIEKind() = 0;
+
+  /// Reference from an __eh_frame FDE atom to the function it's
+  /// describing. Usually pointer-sized and PC-relative, but differs in whether
+  /// it needs to be in relocatable objects.
+  virtual Reference::KindValue unwindRefToFunctionKind() = 0;
+
+  /// Reference from an __unwind_info entry of dwarfCompactUnwindType to the
+  /// required __eh_frame entry. On current architectures, the low 24 bits
+  /// represent the offset of the function's FDE entry from the start of
+  /// __eh_frame.
+  virtual Reference::KindValue unwindRefToEhFrameKind() = 0;
+
+  /// Returns a pointer sized reference kind.  On 64-bit targets this will
+  /// likely be something like pointer64, and pointer32 on 32-bit targets.
+  virtual Reference::KindValue pointerKind() = 0;
+
+  virtual const Atom *fdeTargetFunction(const DefinedAtom *fde);
+
+  /// Used by normalizedFromAtoms() to know where to generated rebasing and
+  /// binding info in final executables.
+  virtual bool isPointer(const Reference &) = 0;
+
+  /// Used by normalizedFromAtoms() to know where to generated lazy binding
+  /// info in final executables.
+  virtual bool isLazyPointer(const Reference &);
+
+  /// Returns true if the specified relocation is paired to the next relocation.
+  virtual bool isPairedReloc(const normalized::Relocation &) = 0;
+
+  /// Prototype for a helper function.  Given a sectionIndex and address,
+  /// finds the atom and offset with that atom of that address.
+  typedef std::function<llvm::Error (uint32_t sectionIndex, uint64_t addr,
+                        const lld::Atom **, Reference::Addend *)>
+                        FindAtomBySectionAndAddress;
+
+  /// Prototype for a helper function.  Given a symbolIndex, finds the atom
+  /// representing that symbol.
+  typedef std::function<llvm::Error (uint32_t symbolIndex,
+                        const lld::Atom **)> FindAtomBySymbolIndex;
+
+  /// Analyzes a relocation from a .o file and returns the info
+  /// (kind, target, addend) needed to instantiate a Reference.
+  /// Two helper functions are passed as parameters to find the target atom
+  /// given a symbol index or address.
+  virtual llvm::Error
+          getReferenceInfo(const normalized::Relocation &reloc,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool isBigEndian,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) = 0;
+
+  /// Analyzes a pair of relocations from a .o file and returns the info
+  /// (kind, target, addend) needed to instantiate a Reference.
+  /// Two helper functions are passed as parameters to find the target atom
+  /// given a symbol index or address.
+  virtual llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool isBig, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) = 0;
+
+  /// Prototype for a helper function.  Given an atom, finds the symbol table
+  /// index for it in the output file.
+  typedef std::function<uint32_t (const Atom &atom)> FindSymbolIndexForAtom;
+
+  /// Prototype for a helper function.  Given an atom, finds the index
+  /// of the section that will contain the atom.
+  typedef std::function<uint32_t (const Atom &atom)> FindSectionIndexForAtom;
+
+  /// Prototype for a helper function.  Given an atom, finds the address
+  /// assigned to it in the output file.
+  typedef std::function<uint64_t (const Atom &atom)> FindAddressForAtom;
+
+  /// Some architectures require local symbols on anonymous atoms.
+  virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) {
+    return false;
+  }
+
+  /// Copy raw content then apply all fixup References on an Atom.
+  virtual void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                                   FindAddressForAtom findAddress,
+                                   FindAddressForAtom findSectionAddress,
+                                   uint64_t imageBaseAddress,
+                          llvm::MutableArrayRef<uint8_t> atomContentBuffer) = 0;
+
+  /// Used in -r mode to convert a Reference to a mach-o relocation.
+  virtual void appendSectionRelocations(const DefinedAtom &atom,
+                                        uint64_t atomSectionOffset,
+                                        const Reference &ref,
+                                        FindSymbolIndexForAtom,
+                                        FindSectionIndexForAtom,
+                                        FindAddressForAtom,
+                                        normalized::Relocations&) = 0;
+
+  /// Add arch-specific References.
+  virtual void addAdditionalReferences(MachODefinedAtom &atom) { }
+
+  // Add Reference for data-in-code marker.
+  virtual void addDataInCodeReference(MachODefinedAtom &atom, uint32_t atomOff,
+                                      uint16_t length, uint16_t kind) { }
+
+  /// Returns true if the specificed Reference value marks the start or end
+  /// of a data-in-code range in an atom.
+  virtual bool isDataInCodeTransition(Reference::KindValue refKind) {
+    return false;
+  }
+
+  /// Returns the Reference value for a Reference that marks that start of
+  /// a data-in-code range.
+  virtual Reference::KindValue dataInCodeTransitionStart(
+                                                const MachODefinedAtom &atom) {
+    return 0;
+  }
+
+  /// Returns the Reference value for a Reference that marks that end of
+  /// a data-in-code range.
+  virtual Reference::KindValue dataInCodeTransitionEnd(
+                                                const MachODefinedAtom &atom) {
+    return 0;
+  }
+
+  /// Only relevant for 32-bit arm archs.
+  virtual bool isThumbFunction(const DefinedAtom &atom) { return false; }
+
+  /// Only relevant for 32-bit arm archs.
+  virtual const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
+                                        const DefinedAtom &) {
+    llvm_unreachable("shims only support on arm");
+  }
+
+  /// Does a given unwind-cfi atom represent a CIE (as opposed to an FDE).
+  static bool isDwarfCIE(bool isBig, const DefinedAtom *atom);
+
+  struct ReferenceInfo {
+    Reference::KindArch arch;
+    uint16_t            kind;
+    uint32_t            offset;
+    int32_t             addend;
+  };
+
+  struct OptionalRefInfo {
+    bool                used;
+    uint16_t            kind;
+    uint32_t            offset;
+    int32_t             addend;
+  };
+
+  /// Table of architecture specific information for creating stubs.
+  struct StubInfo {
+    const char*     binderSymbolName;
+    ReferenceInfo   lazyPointerReferenceToHelper;
+    ReferenceInfo   lazyPointerReferenceToFinal;
+    ReferenceInfo   nonLazyPointerReferenceToBinder;
+    uint8_t         codeAlignment;
+
+    uint32_t        stubSize;
+    uint8_t         stubBytes[16];
+    ReferenceInfo   stubReferenceToLP;
+    OptionalRefInfo optStubReferenceToLP;
+
+    uint32_t        stubHelperSize;
+    uint8_t         stubHelperBytes[16];
+    ReferenceInfo   stubHelperReferenceToImm;
+    ReferenceInfo   stubHelperReferenceToHelperCommon;
+
+    DefinedAtom::ContentType stubHelperImageCacheContentType;
+
+    uint32_t        stubHelperCommonSize;
+    uint8_t         stubHelperCommonAlignment;
+    uint8_t         stubHelperCommonBytes[36];
+    ReferenceInfo   stubHelperCommonReferenceToCache;
+    OptionalRefInfo optStubHelperCommonReferenceToCache;
+    ReferenceInfo   stubHelperCommonReferenceToBinder;
+    OptionalRefInfo optStubHelperCommonReferenceToBinder;
+  };
+
+  virtual const StubInfo &stubInfo() = 0;
+
+protected:
+  ArchHandler();
+
+  static std::unique_ptr<mach_o::ArchHandler> create_x86_64();
+  static std::unique_ptr<mach_o::ArchHandler> create_x86();
+  static std::unique_ptr<mach_o::ArchHandler> create_arm();
+  static std::unique_ptr<mach_o::ArchHandler> create_arm64();
+
+  // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
+  typedef uint16_t RelocPattern;
+  enum {
+    rScattered = 0x8000,
+    rPcRel     = 0x4000,
+    rExtern    = 0x2000,
+    rLength1   = 0x0000,
+    rLength2   = 0x0100,
+    rLength4   = 0x0200,
+    rLength8   = 0x0300,
+    rLenArmLo  = rLength1,
+    rLenArmHi  = rLength2,
+    rLenThmbLo = rLength4,
+    rLenThmbHi = rLength8
+  };
+  /// Extract RelocPattern from normalized mach-o relocation.
+  static RelocPattern relocPattern(const normalized::Relocation &reloc);
+  /// Create normalized Relocation initialized from pattern.
+  static normalized::Relocation relocFromPattern(RelocPattern pattern);
+  /// One liner to add a relocation.
+  static void appendReloc(normalized::Relocations &relocs, uint32_t offset,
+                          uint32_t symbol, uint32_t value,
+                          RelocPattern pattern);
+
+
+  static int16_t  readS16(const uint8_t *addr, bool isBig);
+  static int32_t  readS32(const uint8_t *addr, bool isBig);
+  static uint32_t readU32(const uint8_t *addr, bool isBig);
+  static int64_t  readS64(const uint8_t *addr, bool isBig);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
new file mode 100644 (file)
index 0000000..7d15448
--- /dev/null
@@ -0,0 +1,1519 @@
+//===- lib/FileFormat/MachO/ArchHandler_arm.cpp ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::little32_t;
+
+
+class ArchHandler_arm : public ArchHandler {
+public:
+  ArchHandler_arm() = default;
+  ~ArchHandler_arm() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
+
+  const ArchHandler::StubInfo &stubInfo() override;
+  bool isCallSite(const Reference &) override;
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+  bool isNonCallBranch(const Reference &) override;
+
+  bool needsCompactUnwind() override {
+    return false;
+  }
+  Reference::KindValue imageOffsetKind() override {
+    return invalid;
+  }
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return invalid;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    // FIXME
+    return -1;
+  }
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool swap,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBaseAddress,
+                           llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom,
+                                FindSectionIndexForAtom,
+                                FindAddressForAtom,
+                                normalized::Relocations &) override;
+
+  void addAdditionalReferences(MachODefinedAtom &atom) override;
+
+  bool isDataInCodeTransition(Reference::KindValue refKind) override {
+    switch (refKind) {
+    case modeThumbCode:
+    case modeArmCode:
+    case modeData:
+      return true;
+    default:
+      return false;
+      break;
+    }
+  }
+
+  Reference::KindValue dataInCodeTransitionStart(
+                                        const MachODefinedAtom &atom) override {
+    return modeData;
+  }
+
+  Reference::KindValue dataInCodeTransitionEnd(
+                                        const MachODefinedAtom &atom) override {
+    return atom.isThumb() ? modeThumbCode : modeArmCode;
+  }
+
+  bool isThumbFunction(const DefinedAtom &atom) override;
+  const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
+                                const DefinedAtom &) override;
+
+private:
+  friend class Thumb2ToArmShimAtom;
+  friend class ArmToThumbShimAtom;
+
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfoArmPIC;
+
+  enum ArmKind : Reference::KindValue {
+    invalid,               /// for error condition
+
+    modeThumbCode,         /// Content starting at this offset is thumb.
+    modeArmCode,           /// Content starting at this offset is arm.
+    modeData,              /// Content starting at this offset is data.
+
+    // Kinds found in mach-o .o files:
+    thumb_bl22,            /// ex: bl _foo
+    thumb_b22,             /// ex: b _foo
+    thumb_movw,            /// ex: movw        r1, :lower16:_foo
+    thumb_movt,            /// ex: movt        r1, :lower16:_foo
+    thumb_movw_funcRel,    /// ex: movw        r1, :lower16:(_foo-(L1+4))
+    thumb_movt_funcRel,    /// ex: movt r1, :upper16:(_foo-(L1+4))
+    arm_bl24,              /// ex: bl _foo
+    arm_b24,               /// ex: b _foo
+    arm_movw,              /// ex: movw        r1, :lower16:_foo
+    arm_movt,              /// ex: movt        r1, :lower16:_foo
+    arm_movw_funcRel,      /// ex: movw        r1, :lower16:(_foo-(L1+4))
+    arm_movt_funcRel,      /// ex: movt r1, :upper16:(_foo-(L1+4))
+    pointer32,             /// ex: .long _foo
+    delta32,               /// ex: .long _foo - .
+
+    // Kinds introduced by Passes:
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+  };
+
+  // Utility functions for inspecting/updating instructions.
+  static bool isThumbMovw(uint32_t instruction);
+  static bool isThumbMovt(uint32_t instruction);
+  static bool isArmMovw(uint32_t instruction);
+  static bool isArmMovt(uint32_t instruction);
+  static int32_t getDisplacementFromThumbBranch(uint32_t instruction, uint32_t);
+  static int32_t getDisplacementFromArmBranch(uint32_t instruction);
+  static uint16_t getWordFromThumbMov(uint32_t instruction);
+  static uint16_t getWordFromArmMov(uint32_t instruction);
+  static uint32_t clearThumbBit(uint32_t value, const Atom *target);
+  static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp,
+                                             bool targetIsThumb);
+  static uint32_t setDisplacementInThumbBranch(uint32_t instr, uint32_t ia,
+                                               int32_t disp, bool targetThumb);
+  static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
+  static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
+
+  StringRef stubName(const DefinedAtom &);
+  bool useExternalRelocationTo(const Atom &target);
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress, bool &thumbMode,
+                       bool targetIsThumb);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress,
+                             uint64_t targetAddress,
+                             uint64_t inAtomAddress, bool &thumbMode,
+                             bool targetIsThumb);
+};
+
+//===----------------------------------------------------------------------===//
+//  ArchHandler_arm
+//===----------------------------------------------------------------------===//
+
+const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid),
+  LLD_KIND_STRING_ENTRY(modeThumbCode),
+  LLD_KIND_STRING_ENTRY(modeArmCode),
+  LLD_KIND_STRING_ENTRY(modeData),
+  LLD_KIND_STRING_ENTRY(thumb_bl22),
+  LLD_KIND_STRING_ENTRY(thumb_b22),
+  LLD_KIND_STRING_ENTRY(thumb_movw),
+  LLD_KIND_STRING_ENTRY(thumb_movt),
+  LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
+  LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
+  LLD_KIND_STRING_ENTRY(arm_bl24),
+  LLD_KIND_STRING_ENTRY(arm_b24),
+  LLD_KIND_STRING_ENTRY(arm_movw),
+  LLD_KIND_STRING_ENTRY(arm_movt),
+  LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
+  LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
+  LLD_KIND_STRING_ENTRY(pointer32),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
+  "dyld_stub_binder",
+
+  // References in lazy pointer
+  { Reference::KindArch::ARM, pointer32, 0, 0 },
+  { Reference::KindArch::ARM, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::ARM, pointer32, 0, 0 },
+
+  // arm code alignment 2^2
+  2,
+
+  // Stub size and code
+  16,
+  { 0x04, 0xC0, 0x9F, 0xE5,       //   ldr ip, pc + 12
+    0x0C, 0xC0, 0x8F, 0xE0,       //  add ip, pc, ip
+    0x00, 0xF0, 0x9C, 0xE5,       //   ldr pc, [ip]
+    0x00, 0x00, 0x00, 0x00 },     //   .long L_foo$lazy_ptr - (L1$scv + 8)
+  { Reference::KindArch::ARM, delta32, 12, 0 },
+  { false, 0, 0, 0 },
+
+  // Stub Helper size and code
+  12,
+  { 0x00, 0xC0, 0x9F, 0xE5,       // ldr   ip, [pc, #0]
+    0x00, 0x00, 0x00, 0xEA,       // b      _helperhelper
+    0x00, 0x00, 0x00, 0x00 },     // .long  lazy-info-offset
+  { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
+  { Reference::KindArch::ARM, arm_b24, 4, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeGOT,
+
+  // Stub Helper-Common size and code
+  36,
+  // Stub helper alignment
+  2,
+       { // push lazy-info-offset
+    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
+               // push address of dyld_mageLoaderCache
+    0x10, 0xC0, 0x9F, 0xE5,       // ldr       ip, L1
+    0x0C, 0xC0, 0x8F, 0xE0,       // add       ip, pc, ip
+    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
+               // jump through dyld_stub_binder
+    0x08, 0xC0, 0x9F, 0xE5,       // ldr       ip, L2
+    0x0C, 0xC0, 0x8F, 0xE0,       // add       ip, pc, ip
+    0x00, 0xF0, 0x9C, 0xE5,       // ldr       pc, [ip]
+    0x00, 0x00, 0x00, 0x00,       // L1: .long fFastStubGOTAtom - (helper+16)
+    0x00, 0x00, 0x00, 0x00 },     // L2: .long dyld_stub_binder - (helper+28)
+  { Reference::KindArch::ARM, delta32, 28, 0xC },
+  { false, 0, 0, 0 },
+  { Reference::KindArch::ARM, delta32, 32, 0x04 },
+  { false, 0, 0, 0 }
+};
+
+const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
+  // If multiple kinds of stubs are supported, select which StubInfo here.
+  return _sStubInfoArmPIC;
+}
+
+bool ArchHandler_arm::isCallSite(const Reference &ref) {
+  switch (ref.kindValue()) {
+  case thumb_b22:
+  case thumb_bl22:
+  case arm_b24:
+  case arm_bl24:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool ArchHandler_arm::isPointer(const Reference &ref) {
+  return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_arm::isNonCallBranch(const Reference &ref) {
+  switch (ref.kindValue()) {
+  case thumb_b22:
+  case arm_b24:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
+  switch (reloc.type) {
+  case ARM_RELOC_SECTDIFF:
+  case ARM_RELOC_LOCAL_SECTDIFF:
+  case ARM_RELOC_HALF_SECTDIFF:
+  case ARM_RELOC_HALF:
+    return true;
+  default:
+    return false;
+  }
+}
+
+/// Trace references from stub atom to lazy pointer to target and get its name.
+StringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) {
+  assert(stubAtom.contentType() == DefinedAtom::typeStub);
+  for (const Reference *ref : stubAtom) {
+    if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) {
+      if (lp->contentType() != DefinedAtom::typeLazyPointer)
+        continue;
+      for (const Reference *ref2 : *lp) {
+        if (ref2->kindValue() != lazyPointer)
+          continue;
+        return ref2->target()->name();
+      }
+    }
+  }
+  return "stub";
+}
+
+/// Extract displacement from an ARM b/bl/blx instruction.
+int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
+  // Sign-extend imm24
+  int32_t displacement = (instruction & 0x00FFFFFF) << 2;
+  if ((displacement & 0x02000000) != 0)
+    displacement |= 0xFC000000;
+  // If this is BLX and H bit set, add 2.
+  if ((instruction & 0xFF000000) == 0xFB000000)
+    displacement += 2;
+  return displacement;
+}
+
+/// Update an ARM b/bl/blx instruction, switching bl <-> blx as needed.
+uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
+                                                     int32_t displacement,
+                                                     bool targetIsThumb) {
+  assert((displacement <= 33554428) && (displacement > (-33554432))
+                                              && "arm branch out of range");
+  bool is_blx = ((instruction & 0xF0000000) == 0xF0000000);
+  uint32_t newInstruction = (instruction & 0xFF000000);
+  uint32_t h = 0;
+  if (targetIsThumb) {
+    // Force use of BLX.
+    newInstruction = 0xFA000000;
+    if (!is_blx) {
+      assert(((instruction & 0xF0000000) == 0xE0000000)
+                                                   && "no conditional arm blx");
+      assert(((instruction & 0xFF000000) == 0xEB000000)
+                                             && "no arm pc-rel BX instruction");
+    }
+    if (displacement & 2)
+      h = 1;
+  }
+  else {
+    // Force use of B/BL.
+    if (is_blx)
+      newInstruction = 0xEB000000;
+  }
+  newInstruction |= (h << 24) | ((displacement >> 2) & 0x00FFFFFF);
+  return newInstruction;
+}
+
+/// Extract displacement from a thumb b/bl/blx instruction.
+int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction,
+                                                        uint32_t instrAddr) {
+  bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+  uint32_t s = (instruction >> 10) & 0x1;
+  uint32_t j1 = (instruction >> 29) & 0x1;
+  uint32_t j2 = (instruction >> 27) & 0x1;
+  uint32_t imm10 = instruction & 0x3FF;
+  uint32_t imm11 = (instruction >> 16) & 0x7FF;
+  uint32_t i1 = (j1 == s);
+  uint32_t i2 = (j2 == s);
+  uint32_t dis =
+      (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+  int32_t sdis = dis;
+  int32_t result = s ? (sdis | 0xFE000000) : sdis;
+  if (is_blx && (instrAddr & 0x2)) {
+    // The thumb blx instruction always has low bit of imm11 as zero.  The way
+    // a 2-byte aligned blx can branch to a 4-byte aligned ARM target is that
+    // the blx instruction always 4-byte aligns the pc before adding the
+    // displacement from the blx.  We must emulate that when decoding this.
+    result -= 2;
+  }
+  return result;
+}
+
+/// Update a thumb b/bl/blx instruction, switching bl <-> blx as needed.
+uint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction,
+                                                       uint32_t instrAddr,
+                                                       int32_t displacement,
+                                                       bool targetIsThumb) {
+  assert((displacement <= 16777214) && (displacement > (-16777216))
+                                              && "thumb branch out of range");
+       bool is_bl = ((instruction & 0xD000F800) == 0xD000F000);
+       bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+       bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
+  uint32_t newInstruction = (instruction & 0xD000F800);
+  if (is_bl || is_blx) {
+    if (targetIsThumb) {
+      newInstruction = 0xD000F000; // Use bl
+    } else {
+      newInstruction = 0xC000F000; // Use blx
+      // See note in getDisplacementFromThumbBranch() about blx.
+      if (instrAddr & 0x2)
+        displacement += 2;
+    }
+  } else if (is_b) {
+    assert(targetIsThumb && "no pc-rel thumb branch instruction that "
+                             "switches to arm mode");
+  }
+  else {
+    llvm_unreachable("thumb branch22 reloc on a non-branch instruction");
+  }
+  uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
+  uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
+  uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
+  uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
+  uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
+  uint32_t j1 = (i1 == s);
+  uint32_t j2 = (i2 == s);
+  uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+  uint32_t firstDisp = (s << 10) | imm10;
+  newInstruction |= (nextDisp << 16) | firstDisp;
+  return newInstruction;
+}
+
+bool ArchHandler_arm::isThumbMovw(uint32_t instruction) {
+  return (instruction & 0x8000FBF0) == 0x0000F240;
+}
+
+bool ArchHandler_arm::isThumbMovt(uint32_t instruction) {
+  return (instruction & 0x8000FBF0) == 0x0000F2C0;
+}
+
+bool ArchHandler_arm::isArmMovw(uint32_t instruction) {
+  return (instruction & 0x0FF00000) == 0x03000000;
+}
+
+bool ArchHandler_arm::isArmMovt(uint32_t instruction) {
+  return (instruction & 0x0FF00000) == 0x03400000;
+}
+
+uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
+  assert(isThumbMovw(instruction) || isThumbMovt(instruction));
+  uint32_t i = ((instruction & 0x00000400) >> 10);
+  uint32_t imm4 = (instruction & 0x0000000F);
+  uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+  uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+  return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+}
+
+uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
+  assert(isArmMovw(instruction) || isArmMovt(instruction));
+  uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+  uint32_t imm12 = (instruction & 0x00000FFF);
+  return (imm4 << 12) | imm12;
+}
+
+uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
+  assert(isThumbMovw(instr) || isThumbMovt(instr));
+  uint32_t imm4 = (word & 0xF000) >> 12;
+  uint32_t i =    (word & 0x0800) >> 11;
+  uint32_t imm3 = (word & 0x0700) >> 8;
+  uint32_t imm8 =  word & 0x00FF;
+       return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+}
+
+uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
+  assert(isArmMovw(instr) || isArmMovt(instr));
+  uint32_t imm4 = (word & 0xF000) >> 12;
+  uint32_t imm12 = word & 0x0FFF;
+  return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
+}
+
+uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
+  // The assembler often adds one to the address of a thumb function.
+  // We need to undo that so it does not look like an addend.
+  if (value & 1) {
+    if (isa<DefinedAtom>(target)) {
+      const MachODefinedAtom *machoTarget =
+          reinterpret_cast<const MachODefinedAtom *>(target);
+      if (machoTarget->isThumb())
+        value &= -2; // mask off thumb-bit
+    }
+  }
+  return value;
+}
+
+llvm::Error ArchHandler_arm::getReferenceInfo(
+    const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+    uint64_t fixupAddress, bool isBig,
+    FindAtomBySectionAndAddress atomFromAddress,
+    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+    const lld::Atom **target, Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  uint32_t instruction = *(const ulittle32_t *)fixupContent;
+  int32_t displacement;
+  switch (relocPattern(reloc)) {
+  case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
+    // ex: bl _foo (and _foo is undefined)
+    if ((instruction & 0xD000F800) == 0x9000F000)
+      *kind = thumb_b22;
+    else
+      *kind = thumb_bl22;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // Instruction contains branch to addend.
+    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+    *addend = fixupAddress + 4 + displacement;
+    return llvm::Error::success();
+  case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
+    // ex: bl _foo (and _foo is defined)
+    if ((instruction & 0xD000F800) == 0x9000F000)
+      *kind = thumb_b22;
+    else
+      *kind = thumb_bl22;
+    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+    targetAddress = fixupAddress + 4 + displacement;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
+    // ex: bl _foo+4 (and _foo is defined)
+    if ((instruction & 0xD000F800) == 0x9000F000)
+      *kind = thumb_b22;
+    else
+      *kind = thumb_bl22;
+    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+    targetAddress = fixupAddress + 4 + displacement;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    // reloc.value is target atom's address.  Instruction contains branch
+    // to atom+addend.
+    *addend += (targetAddress - reloc.value);
+    return llvm::Error::success();
+  case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
+    // ex: bl _foo (and _foo is undefined)
+    if (((instruction & 0x0F000000) == 0x0A000000)
+        && ((instruction & 0xF0000000) != 0xF0000000))
+      *kind = arm_b24;
+    else
+      *kind = arm_bl24;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // Instruction contains branch to addend.
+    displacement = getDisplacementFromArmBranch(instruction);
+    *addend = fixupAddress + 8 + displacement;
+    return llvm::Error::success();
+  case ARM_RELOC_BR24 | rPcRel | rLength4:
+    // ex: bl _foo (and _foo is defined)
+    if (((instruction & 0x0F000000) == 0x0A000000)
+        && ((instruction & 0xF0000000) != 0xF0000000))
+      *kind = arm_b24;
+    else
+      *kind = arm_bl24;
+    displacement = getDisplacementFromArmBranch(instruction);
+    targetAddress = fixupAddress + 8 + displacement;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
+    // ex: bl _foo+4 (and _foo is defined)
+    if (((instruction & 0x0F000000) == 0x0A000000)
+        && ((instruction & 0xF0000000) != 0xF0000000))
+      *kind = arm_b24;
+    else
+      *kind = arm_bl24;
+    displacement = getDisplacementFromArmBranch(instruction);
+    targetAddress = fixupAddress + 8 + displacement;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    // reloc.value is target atom's address.  Instruction contains branch
+    // to atom+addend.
+    *addend += (targetAddress - reloc.value);
+    return llvm::Error::success();
+  case ARM_RELOC_VANILLA | rExtern | rLength4:
+    // ex: .long _foo (and _foo is undefined)
+    *kind = pointer32;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = instruction;
+    return llvm::Error::success();
+  case ARM_RELOC_VANILLA | rLength4:
+    // ex: .long _foo (and _foo is defined)
+    *kind = pointer32;
+    if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+      return ec;
+    *addend = clearThumbBit((uint32_t) * addend, *target);
+    return llvm::Error::success();
+  case ARM_RELOC_VANILLA | rScattered | rLength4:
+    // ex: .long _foo+a (and _foo is defined)
+    *kind = pointer32;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend += (clearThumbBit(instruction, *target) - reloc.value);
+    return llvm::Error::success();
+  default:
+    return llvm::make_error<GenericError>("unsupported arm relocation type");
+  }
+  return llvm::Error::success();
+}
+
+llvm::Error
+ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                     const normalized::Relocation &reloc2,
+                                     const DefinedAtom *inAtom,
+                                     uint32_t offsetInAtom,
+                                     uint64_t fixupAddress, bool isBig,
+                                     bool scatterable,
+                                     FindAtomBySectionAndAddress atomFromAddr,
+                                     FindAtomBySymbolIndex atomFromSymbolIndex,
+                                     Reference::KindValue *kind,
+                                     const lld::Atom **target,
+                                     Reference::Addend *addend) {
+  bool pointerDiff = false;
+  bool funcRel;
+  bool top;
+  bool thumbReloc;
+  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenThmbLo):
+    // ex: movw        r1, :lower16:(_x-L1) [thumb mode]
+    *kind = thumb_movw_funcRel;
+    funcRel = true;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenThmbHi):
+    // ex: movt        r1, :upper16:(_x-L1) [thumb mode]
+    *kind = thumb_movt_funcRel;
+    funcRel = true;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenArmLo):
+    // ex: movw        r1, :lower16:(_x-L1) [arm mode]
+    *kind = arm_movw_funcRel;
+    funcRel = true;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLenArmHi):
+    // ex: movt        r1, :upper16:(_x-L1) [arm mode]
+    *kind = arm_movt_funcRel;
+    funcRel = true;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF     | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR     | rLenThmbLo):
+    // ex: movw        r1, :lower16:_x [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF     | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR     | rLenThmbHi):
+    // ex: movt        r1, :upper16:_x [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF     | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR     | rLenArmLo):
+    // ex: movw        r1, :lower16:_x [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF     | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR     | rLenArmHi):
+    // ex: movt        r1, :upper16:_x [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR               | rLenThmbLo):
+    // ex: movw        r1, :lower16:_x+a [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR               | rLenThmbHi):
+    // ex: movt        r1, :upper16:_x+a [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR               | rLenArmLo):
+    // ex: movw        r1, :lower16:_x+a [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR               | rLenArmHi):
+    // ex: movt        r1, :upper16:_x+a [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenThmbLo) << 16 |
+         ARM_RELOC_PAIR             | rLenThmbLo):
+    // ex: movw        r1, :lower16:_undef [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenThmbHi) << 16 |
+         ARM_RELOC_PAIR             | rLenThmbHi):
+    // ex: movt        r1, :upper16:_undef [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenArmLo) << 16 |
+         ARM_RELOC_PAIR             | rLenArmLo):
+    // ex: movw        r1, :lower16:_undef [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLenArmHi) << 16 |
+         ARM_RELOC_PAIR             | rLenArmHi):
+    // ex: movt        r1, :upper16:_undef [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_SECTDIFF       | rScattered | rLength4) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength4):
+  case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength4):
+    // ex: .long _foo - .
+    pointerDiff = true;
+    break;
+  default:
+    return llvm::make_error<GenericError>("unsupported arm relocation pair");
+  }
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint32_t instruction = *(const ulittle32_t *)fixupContent;
+  uint32_t value;
+  uint32_t fromAddress;
+  uint32_t toAddress;
+  uint16_t instruction16;
+  uint16_t other16;
+  const lld::Atom *fromTarget;
+  Reference::Addend offsetInTo;
+  Reference::Addend offsetInFrom;
+  if (pointerDiff) {
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+      return ec;
+    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+      return ec;
+    if (scatterable && (fromTarget != inAtom))
+      return llvm::make_error<GenericError>(
+          "SECTDIFF relocation where subtrahend label is not in atom");
+    *kind = delta32;
+    value = clearThumbBit(instruction, *target);
+    *addend = (int32_t)(value - (toAddress - fixupAddress));
+  } else if (funcRel) {
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+      return ec;
+    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+      return ec;
+    if (fromTarget != inAtom)
+      return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
+                                     " where subtrahend label is not in atom");
+    other16 = (reloc2.offset & 0xFFFF);
+    if (thumbReloc) {
+      if (top) {
+        if (!isThumbMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isThumbMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromThumbMov(instruction);
+    }
+    else {
+      if (top) {
+        if (!isArmMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isArmMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromArmMov(instruction);
+    }
+    if (top)
+      value = (instruction16 << 16) | other16;
+    else
+      value = (other16 << 16) | instruction16;
+    value = clearThumbBit(value, *target);
+    int64_t ta = (int64_t) value - (toAddress - fromAddress);
+    *addend = ta - offsetInFrom;
+    return llvm::Error::success();
+  } else {
+    uint32_t sectIndex;
+    if (thumbReloc) {
+      if (top) {
+        if (!isThumbMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isThumbMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromThumbMov(instruction);
+    }
+    else {
+      if (top) {
+        if (!isArmMovt(instruction))
+          return llvm::make_error<GenericError>("expected movt instruction");
+      }
+      else {
+        if (!isArmMovw(instruction))
+          return llvm::make_error<GenericError>("expected movw instruction");
+      }
+      instruction16 = getWordFromArmMov(instruction);
+    }
+    other16 = (reloc2.offset & 0xFFFF);
+    if (top)
+      value = (instruction16 << 16) | other16;
+    else
+      value = (other16 << 16) | instruction16;
+    if (reloc1.isExtern) {
+      if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
+        return ec;
+      *addend = value;
+    } else {
+      if (reloc1.scattered) {
+        toAddress = reloc1.value;
+        sectIndex = 0;
+      } else {
+        toAddress = value;
+        sectIndex = reloc1.symbol;
+      }
+      if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
+        return ec;
+      *addend = value - toAddress;
+    }
+  }
+
+  return llvm::Error::success();
+}
+
+void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
+                                      uint64_t fixupAddress,
+                                      uint64_t targetAddress,
+                                      uint64_t inAtomAddress,
+                                      bool &thumbMode, bool targetIsThumb) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::ARM);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  int32_t displacement;
+  uint16_t value16;
+  uint32_t value32;
+  switch (static_cast<ArmKind>(ref.kindValue())) {
+  case modeThumbCode:
+    thumbMode = true;
+    break;
+  case modeArmCode:
+    thumbMode = false;
+    break;
+  case modeData:
+    break;
+  case thumb_b22:
+  case thumb_bl22:
+    assert(thumbMode);
+    displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
+                                           displacement, targetIsThumb);
+    *loc32 = value32;
+    break;
+  case thumb_movw:
+    assert(thumbMode);
+    value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt:
+    assert(thumbMode);
+    value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movw_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case arm_b24:
+  case arm_bl24:
+   assert(!thumbMode);
+    displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
+    value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb);
+    *loc32 = value32;
+    break;
+  case arm_movw:
+    assert(!thumbMode);
+    value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt:
+    assert(!thumbMode);
+    value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movw_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    if (targetIsThumb)
+      value16 |= 1;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case pointer32:
+    if (targetIsThumb)
+      *loc32 = targetAddress + ref.addend() + 1;
+    else
+      *loc32 = targetAddress + ref.addend();
+    break;
+  case delta32:
+    if (targetIsThumb)
+      *loc32 = targetAddress - fixupAddress + ref.addend() + 1;
+    else
+      *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case lazyPointer:
+    // do nothing
+    break;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    break;
+  case invalid:
+    llvm_unreachable("invalid ARM Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
+                                          bool relocatable,
+                                          FindAddressForAtom findAddress,
+                                          FindAddressForAtom findSectionAddress,
+                                          uint64_t imageBaseAddress,
+                            llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+  bool thumbMode = false;
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    uint64_t targetAddress = 0;
+    bool targetIsThumb = false;
+    if (const DefinedAtom *defTarg = dyn_cast<DefinedAtom>(target)) {
+      targetAddress = findAddress(*target);
+      targetIsThumb = isThumbFunction(*defTarg);
+    }
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
+                            targetAddress, atomAddress, thumbMode,
+                            targetIsThumb);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
+                      targetAddress, atomAddress, thumbMode, targetIsThumb);
+    }
+  }
+}
+
+bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
+  // Undefined symbols are referenced via external relocations.
+  if (isa<UndefinedAtom>(&target))
+    return true;
+  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+     switch (defAtom->merge()) {
+     case DefinedAtom::mergeAsTentative:
+       // Tentative definitions are referenced via external relocations.
+       return true;
+     case DefinedAtom::mergeAsWeak:
+     case DefinedAtom::mergeAsWeakAndAddressUsed:
+       // Global weak-defs are referenced via external relocations.
+       return (defAtom->scope() == DefinedAtom::scopeGlobal);
+     default:
+       break;
+    }
+  }
+  // Everything else is reference via an internal relocation.
+  return false;
+}
+
+void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *loc,
+                                            uint64_t fixupAddress,
+                                            uint64_t targetAddress,
+                                            uint64_t inAtomAddress,
+                                            bool &thumbMode,
+                                            bool targetIsThumb) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::ARM);
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  int32_t displacement;
+  uint16_t value16;
+  uint32_t value32;
+  bool targetIsUndef = isa<UndefinedAtom>(ref.target());
+  switch (static_cast<ArmKind>(ref.kindValue())) {
+  case modeThumbCode:
+    thumbMode = true;
+    break;
+  case modeArmCode:
+    thumbMode = false;
+    break;
+  case modeData:
+    break;
+  case thumb_b22:
+  case thumb_bl22:
+    assert(thumbMode);
+    if (useExternalReloc)
+      displacement = (ref.addend() - (fixupAddress + 4));
+    else
+      displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
+                                           displacement,
+                                           targetIsUndef || targetIsThumb);
+    *loc32 = value32;
+    break;
+  case thumb_movw:
+    assert(thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() & 0xFFFF;
+    else
+      value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt:
+    assert(thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() >> 16;
+    else
+      value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movw_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case thumb_movt_funcRel:
+    assert(thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromThumbMov(*loc32, value16);
+    break;
+  case arm_b24:
+  case arm_bl24:
+    assert(!thumbMode);
+    if (useExternalReloc)
+      displacement = (ref.addend() - (fixupAddress + 8));
+    else
+      displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
+    value32 = setDisplacementInArmBranch(*loc32, displacement,
+                                         targetIsThumb);
+    *loc32 = value32;
+    break;
+  case arm_movw:
+    assert(!thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() & 0xFFFF;
+    else
+      value16 = (targetAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt:
+    assert(!thumbMode);
+    if (useExternalReloc)
+      value16 = ref.addend() >> 16;
+    else
+      value16 = (targetAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movw_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case arm_movt_funcRel:
+    assert(!thumbMode);
+    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+    *loc32 = setWordFromArmMov(*loc32, value16);
+    break;
+  case pointer32:
+    *loc32 = targetAddress + ref.addend();
+    break;
+  case delta32:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  case invalid:
+    llvm_unreachable("invalid ARM Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_arm::appendSectionRelocations(
+                                   const DefinedAtom &atom,
+                                   uint64_t atomSectionOffset,
+                                   const Reference &ref,
+                                   FindSymbolIndexForAtom symbolIndexForAtom,
+                                   FindSectionIndexForAtom sectionIndexForAtom,
+                                   FindAddressForAtom addressForAtom,
+                                   normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::ARM);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  uint32_t targetAtomAddress;
+  uint32_t fromAtomAddress;
+  uint16_t other16;
+  switch (static_cast<ArmKind>(ref.kindValue())) {
+  case modeThumbCode:
+  case modeArmCode:
+  case modeData:
+    // Do nothing.
+    break;
+  case thumb_b22:
+  case thumb_bl22:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_THUMB_RELOC_BR22 | rExtern    | rPcRel | rLength4);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_THUMB_RELOC_BR22 |              rPcRel | rLength4);
+    }
+    break;
+  case thumb_movw:
+    if (useExternalReloc) {
+      other16 = ref.addend() >> 16;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenThmbLo);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbLo);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                  ARM_RELOC_HALF | rScattered | rLenThmbLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbLo);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_HALF              | rLenThmbLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbLo);
+      }
+    }
+    break;
+  case thumb_movt:
+    if (useExternalReloc) {
+      other16 = ref.addend() & 0xFFFF;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenThmbHi);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenThmbHi);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                    ARM_RELOC_HALF | rScattered | rLenThmbHi);
+        appendReloc(relocs, other16, 0, 0,
+                    ARM_RELOC_PAIR              | rLenThmbHi);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                    ARM_RELOC_HALF              | rLenThmbHi);
+        appendReloc(relocs, other16, 0, 0,
+                    ARM_RELOC_PAIR              | rLenThmbHi);
+      }
+    }
+    break;
+  case thumb_movw_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenThmbLo);
+    break;
+  case thumb_movt_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenThmbHi);
+    break;
+  case arm_b24:
+  case arm_bl24:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_BR24 | rExtern    | rPcRel | rLength4);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  ARM_RELOC_BR24 | rScattered | rPcRel | rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_BR24 |              rPcRel | rLength4);
+    }
+    break;
+  case arm_movw:
+    if (useExternalReloc) {
+      other16 = ref.addend() >> 16;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenArmLo);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmLo);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                  ARM_RELOC_HALF | rScattered | rLenArmLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmLo);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) >> 16;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_HALF              | rLenArmLo);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmLo);
+      }
+    }
+    break;
+  case arm_movt:
+    if (useExternalReloc) {
+      other16 = ref.addend() & 0xFFFF;
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM_RELOC_HALF | rExtern    | rLenArmHi);
+      appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmHi);
+    } else {
+      targetAtomAddress = addressForAtom(*ref.target());
+      if (ref.addend() != 0) {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                  ARM_RELOC_HALF | rScattered | rLenArmHi);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmHi);
+      } else {
+        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  ARM_RELOC_HALF              | rLenArmHi);
+        appendReloc(relocs, other16, 0, 0,
+                  ARM_RELOC_PAIR              | rLenArmHi);
+      }
+    }
+    break;
+  case arm_movw_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenArmLo);
+    break;
+  case arm_movt_funcRel:
+    fromAtomAddress = addressForAtom(atom);
+    targetAtomAddress = addressForAtom(*ref.target());
+    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi);
+    appendReloc(relocs, other16, 0, fromAtomAddress,
+                ARM_RELOC_PAIR          | rScattered | rLenArmHi);
+    break;
+  case pointer32:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()),  0,
+                ARM_RELOC_VANILLA |    rExtern     |  rLength4);
+    }
+    else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                ARM_RELOC_VANILLA |    rScattered  |  rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                ARM_RELOC_VANILLA |                   rLength4);
+    }
+    break;
+  case delta32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              ARM_RELOC_SECTDIFF  |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+                                                           ref.offsetInAtom(),
+              ARM_RELOC_PAIR      |  rScattered    | rLength4);
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  case invalid:
+    llvm_unreachable("invalid ARM Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
+  if (atom.isThumb()) {
+    atom.addReference(Reference::KindNamespace::mach_o,
+                      Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
+  }
+}
+
+bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
+  for (const Reference *ref : atom) {
+    if (ref->offsetInAtom() != 0)
+      return false;
+    if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
+      continue;
+    assert(ref->kindArch() == Reference::KindArch::ARM);
+    if (ref->kindValue() == modeThumbCode)
+      return true;
+  }
+  return false;
+}
+
+class Thumb2ToArmShimAtom : public SimpleDefinedAtom {
+public:
+  Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
+                      const DefinedAtom &target)
+      : SimpleDefinedAtom(file) {
+    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+                 ArchHandler_arm::modeThumbCode, 0, this, 0);
+    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+                 ArchHandler_arm::delta32, 8, &target, 0);
+    std::string name = std::string(targetName) + "$shim";
+    StringRef tmp(name);
+    _name = tmp.copy(file.allocator());
+  }
+
+  ~Thumb2ToArmShimAtom() override = default;
+
+  StringRef name() const override {
+    return _name;
+  }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeCode;
+  }
+
+  Alignment alignment() const override { return 4; }
+
+  uint64_t size() const override {
+    return 12;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t bytes[] =
+    { 0xDF, 0xF8, 0x04, 0xC0,       //  ldr ip, pc + 4
+      0xFF, 0x44,                   //  add ip, pc, ip
+      0x60, 0x47,                   //  ldr pc, [ip]
+      0x00, 0x00, 0x00, 0x00 };     //  .long target - this
+    assert(sizeof(bytes) == size());
+    return llvm::makeArrayRef(bytes, sizeof(bytes));
+  }
+private:
+  StringRef _name;
+};
+
+class ArmToThumbShimAtom : public SimpleDefinedAtom {
+public:
+  ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
+                     const DefinedAtom &target)
+      : SimpleDefinedAtom(file) {
+    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+                 ArchHandler_arm::delta32, 12, &target, 0);
+    std::string name = std::string(targetName) + "$shim";
+    StringRef tmp(name);
+    _name = tmp.copy(file.allocator());
+  }
+
+  ~ArmToThumbShimAtom() override = default;
+
+  StringRef name() const override {
+    return _name;
+  }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeCode;
+  }
+
+  Alignment alignment() const override { return 4; }
+
+  uint64_t size() const override {
+    return 16;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t bytes[] =
+    { 0x04, 0xC0, 0x9F, 0xE5,       //  ldr ip, pc + 4
+      0x0C, 0xC0, 0x8F, 0xE0,       //  add ip, pc, ip
+      0x1C, 0xFF, 0x2F, 0xE1,       //  ldr pc, [ip]
+      0x00, 0x00, 0x00, 0x00 };     //  .long target - this
+    assert(sizeof(bytes) == size());
+    return llvm::makeArrayRef(bytes, sizeof(bytes));
+  }
+private:
+  StringRef _name;
+};
+
+const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
+                                               bool thumbToArm,
+                                               const DefinedAtom &target) {
+  bool isStub = (target.contentType() == DefinedAtom::typeStub);
+  StringRef targetName = isStub ? stubName(target) : target.name();
+  if (thumbToArm)
+    return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target);
+  else
+    return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
new file mode 100644 (file)
index 0000000..10360b5
--- /dev/null
@@ -0,0 +1,894 @@
+//===- lib/FileFormat/MachO/ArchHandler_arm64.cpp -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::ulittle64_t;
+
+using llvm::support::little32_t;
+using llvm::support::little64_t;
+
+class ArchHandler_arm64 : public ArchHandler {
+public:
+  ArchHandler_arm64() = default;
+  ~ArchHandler_arm64() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override {
+    return Reference::KindArch::AArch64;
+  }
+
+  /// Used by GOTPass to locate GOT References
+  bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+    if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+      return false;
+    assert(ref.kindArch() == Reference::KindArch::AArch64);
+    switch (ref.kindValue()) {
+    case gotPage21:
+    case gotOffset12:
+      canBypassGOT = true;
+      return true;
+    case delta32ToGOT:
+    case unwindCIEToPersonalityFunction:
+    case imageOffsetGot:
+      canBypassGOT = false;
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  /// Used by GOTPass to update GOT References.
+  void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+    // If GOT slot was instanciated, transform:
+    //   gotPage21/gotOffset12 -> page21/offset12scale8
+    // If GOT slot optimized away, transform:
+    //   gotPage21/gotOffset12 -> page21/addOffset12
+    assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref->kindArch() == Reference::KindArch::AArch64);
+    switch (ref->kindValue()) {
+    case gotPage21:
+      const_cast<Reference *>(ref)->setKindValue(page21);
+      break;
+    case gotOffset12:
+      const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
+                                                 offset12scale8 : addOffset12);
+      break;
+    case delta32ToGOT:
+      const_cast<Reference *>(ref)->setKindValue(delta32);
+      break;
+    case imageOffsetGot:
+      const_cast<Reference *>(ref)->setKindValue(imageOffset);
+      break;
+    default:
+      llvm_unreachable("Not a GOT reference");
+    }
+  }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+
+  bool isCallSite(const Reference &) override;
+  bool isNonCallBranch(const Reference &) override {
+    return false;
+  }
+
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+
+  bool needsCompactUnwind() override {
+    return true;
+  }
+  Reference::KindValue imageOffsetKind() override {
+    return imageOffset;
+  }
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return imageOffsetGot;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return unwindCIEToPersonalityFunction;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return negDelta32;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override {
+    return unwindFDEToFunction;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return unwindInfoToEhFrame;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return pointer64;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    return 0x03000000;
+  }
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool isBig,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool isBig, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
+    return (atom->contentType() == DefinedAtom::typeCString);
+  }
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBaseAddress,
+                    llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom symbolIndexForAtom,
+                                FindSectionIndexForAtom sectionIndexForAtom,
+                                FindAddressForAtom addressForAtom,
+                                normalized::Relocations &relocs) override;
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo _sStubInfo;
+
+  enum Arm64Kind : Reference::KindValue {
+    invalid,               /// for error condition
+
+    // Kinds found in mach-o .o files:
+    branch26,              /// ex: bl   _foo
+    page21,                /// ex: adrp x1, _foo@PAGE
+    offset12,              /// ex: ldrb w0, [x1, _foo@PAGEOFF]
+    offset12scale2,        /// ex: ldrs w0, [x1, _foo@PAGEOFF]
+    offset12scale4,        /// ex: ldr  w0, [x1, _foo@PAGEOFF]
+    offset12scale8,        /// ex: ldr  x0, [x1, _foo@PAGEOFF]
+    offset12scale16,       /// ex: ldr  q0, [x1, _foo@PAGEOFF]
+    gotPage21,             /// ex: adrp x1, _foo@GOTPAGE
+    gotOffset12,           /// ex: ldr  w0, [x1, _foo@GOTPAGEOFF]
+    tlvPage21,             /// ex: adrp x1, _foo@TLVPAGE
+    tlvOffset12,           /// ex: ldr  w0, [x1, _foo@TLVPAGEOFF]
+
+    pointer64,             /// ex: .quad _foo
+    delta64,               /// ex: .quad _foo - .
+    delta32,               /// ex: .long _foo - .
+    negDelta32,            /// ex: .long . - _foo
+    pointer64ToGOT,        /// ex: .quad _foo@GOT
+    delta32ToGOT,          /// ex: .long _foo@GOT - .
+
+    // Kinds introduced by Passes:
+    addOffset12,           /// Location contains LDR to change into ADD.
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+    imageOffset,           /// Location contains offset of atom in final image
+    imageOffsetGot,        /// Location contains offset of GOT entry for atom in
+                           /// final image (typically personality function).
+    unwindCIEToPersonalityFunction,   /// Nearly delta32ToGOT, but cannot be
+                           /// rematerialized in relocatable object
+                           /// (yay for implicit contracts!).
+    unwindFDEToFunction,   /// Nearly delta64, but cannot be rematerialized in
+                           /// relocatable object (yay for implicit contracts!).
+    unwindInfoToEhFrame,   /// Fix low 24 bits of compact unwind encoding to
+                           /// refer to __eh_frame entry.
+  };
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress, uint64_t imageBaseAddress,
+                       FindAddressForAtom findSectionAddress);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress, uint64_t targetAddress,
+                             uint64_t inAtomAddress, bool targetUnnamed);
+
+  // Utility functions for inspecting/updating instructions.
+  static uint32_t setDisplacementInBranch26(uint32_t instr, int32_t disp);
+  static uint32_t setDisplacementInADRP(uint32_t instr, int64_t disp);
+  static Arm64Kind offset12KindFromInstruction(uint32_t instr);
+  static uint32_t setImm12(uint32_t instr, uint32_t offset);
+};
+
+const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid),
+  LLD_KIND_STRING_ENTRY(branch26),
+  LLD_KIND_STRING_ENTRY(page21),
+  LLD_KIND_STRING_ENTRY(offset12),
+  LLD_KIND_STRING_ENTRY(offset12scale2),
+  LLD_KIND_STRING_ENTRY(offset12scale4),
+  LLD_KIND_STRING_ENTRY(offset12scale8),
+  LLD_KIND_STRING_ENTRY(offset12scale16),
+  LLD_KIND_STRING_ENTRY(gotPage21),
+  LLD_KIND_STRING_ENTRY(gotOffset12),
+  LLD_KIND_STRING_ENTRY(tlvPage21),
+  LLD_KIND_STRING_ENTRY(tlvOffset12),
+  LLD_KIND_STRING_ENTRY(pointer64),
+  LLD_KIND_STRING_ENTRY(delta64),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(negDelta32),
+  LLD_KIND_STRING_ENTRY(pointer64ToGOT),
+  LLD_KIND_STRING_ENTRY(delta32ToGOT),
+
+  LLD_KIND_STRING_ENTRY(addOffset12),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_ENTRY(imageOffset),
+  LLD_KIND_STRING_ENTRY(imageOffsetGot),
+  LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction),
+  LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
+  LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references
+  { Reference::KindArch::AArch64, pointer64, 0, 0 },
+  { Reference::KindArch::AArch64, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::AArch64, pointer64, 0, 0 },
+
+  // arm64 code alignment 2^1
+  1,
+
+  // Stub size and code
+  12,
+  { 0x10, 0x00, 0x00, 0x90,   // ADRP  X16, lazy_pointer@page
+    0x10, 0x02, 0x40, 0xF9,   // LDR   X16, [X16, lazy_pointer@pageoff]
+    0x00, 0x02, 0x1F, 0xD6 }, // BR    X16
+  { Reference::KindArch::AArch64, page21, 0, 0 },
+  { true,                         offset12scale8, 4, 0 },
+
+  // Stub Helper size and code
+  12,
+  { 0x50, 0x00, 0x00, 0x18,   //      LDR   W16, L0
+    0x00, 0x00, 0x00, 0x14,   //      LDR   B  helperhelper
+    0x00, 0x00, 0x00, 0x00 }, // L0: .long 0
+  { Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
+  { Reference::KindArch::AArch64, branch26, 4, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeGOT,
+
+  // Stub Helper-Common size and code
+  24,
+  // Stub helper alignment
+  2,
+  { 0x11, 0x00, 0x00, 0x90,   //  ADRP  X17, dyld_ImageLoaderCache@page
+    0x31, 0x02, 0x00, 0x91,   //  ADD   X17, X17, dyld_ImageLoaderCache@pageoff
+    0xF0, 0x47, 0xBF, 0xA9,   //  STP   X16/X17, [SP, #-16]!
+    0x10, 0x00, 0x00, 0x90,   //  ADRP  X16, _fast_lazy_bind@page
+    0x10, 0x02, 0x40, 0xF9,   //  LDR   X16, [X16,_fast_lazy_bind@pageoff]
+    0x00, 0x02, 0x1F, 0xD6 }, //  BR    X16
+  { Reference::KindArch::AArch64, page21,   0, 0 },
+  { true,                         offset12, 4, 0 },
+  { Reference::KindArch::AArch64, page21,   12, 0 },
+  { true,                         offset12scale8, 16, 0 }
+};
+
+bool ArchHandler_arm64::isCallSite(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  return (ref.kindValue() == branch26);
+}
+
+bool ArchHandler_arm64::isPointer(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  Reference::KindValue kind = ref.kindValue();
+  return (kind == pointer64);
+}
+
+bool ArchHandler_arm64::isPairedReloc(const Relocation &r) {
+  return ((r.type == ARM64_RELOC_ADDEND) || (r.type == ARM64_RELOC_SUBTRACTOR));
+}
+
+uint32_t ArchHandler_arm64::setDisplacementInBranch26(uint32_t instr,
+                                                      int32_t displacement) {
+  assert((displacement <= 134217727) && (displacement > (-134217728)) &&
+         "arm64 branch out of range");
+  return (instr & 0xFC000000) | ((uint32_t)(displacement >> 2) & 0x03FFFFFF);
+}
+
+uint32_t ArchHandler_arm64::setDisplacementInADRP(uint32_t instruction,
+                                                  int64_t displacement) {
+  assert((displacement <= 0x100000000LL) && (displacement > (-0x100000000LL)) &&
+         "arm64 ADRP out of range");
+  assert(((instruction & 0x9F000000) == 0x90000000) &&
+         "reloc not on ADRP instruction");
+  uint32_t immhi = (displacement >> 9) & (0x00FFFFE0);
+  uint32_t immlo = (displacement << 17) & (0x60000000);
+  return (instruction & 0x9F00001F) | immlo | immhi;
+}
+
+ArchHandler_arm64::Arm64Kind
+ArchHandler_arm64::offset12KindFromInstruction(uint32_t instruction) {
+  if (instruction & 0x08000000) {
+    switch ((instruction >> 30) & 0x3) {
+    case 0:
+      if ((instruction & 0x04800000) == 0x04800000)
+        return offset12scale16;
+      return offset12;
+    case 1:
+      return offset12scale2;
+    case 2:
+      return offset12scale4;
+    case 3:
+      return offset12scale8;
+    }
+  }
+  return offset12;
+}
+
+uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
+  assert(((offset & 0xFFFFF000) == 0) && "imm12 offset out of range");
+  uint32_t imm12 = offset << 10;
+  return (instruction & 0xFFC003FF) | imm12;
+}
+
+llvm::Error ArchHandler_arm64::getReferenceInfo(
+    const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+    uint64_t fixupAddress, bool isBig,
+    FindAtomBySectionAndAddress atomFromAddress,
+    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+    const lld::Atom **target, Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  switch (relocPattern(reloc)) {
+  case ARM64_RELOC_BRANCH26           | rPcRel | rExtern | rLength4:
+    // ex: bl _foo
+    *kind = branch26;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_PAGE21             | rPcRel | rExtern | rLength4:
+    // ex: adrp x1, _foo@PAGE
+    *kind = page21;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_PAGEOFF12                   | rExtern | rLength4:
+    // ex: ldr x0, [x1, _foo@PAGEOFF]
+    *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_GOT_LOAD_PAGE21    | rPcRel | rExtern | rLength4:
+    // ex: adrp x1, _foo@GOTPAGE
+    *kind = gotPage21;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_GOT_LOAD_PAGEOFF12          | rExtern | rLength4:
+    // ex: ldr x0, [x1, _foo@GOTPAGEOFF]
+    *kind = gotOffset12;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_TLVP_LOAD_PAGE21   | rPcRel | rExtern | rLength4:
+    // ex: adrp x1, _foo@TLVPAGE
+    *kind = tlvPage21;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_TLVP_LOAD_PAGEOFF12         | rExtern | rLength4:
+    // ex: ldr x0, [x1, _foo@TLVPAGEOFF]
+    *kind = tlvOffset12;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_UNSIGNED                    | rExtern | rLength8:
+    // ex: .quad _foo + N
+    *kind = pointer64;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const little64_t *)fixupContent;
+    return llvm::Error::success();
+  case ARM64_RELOC_UNSIGNED                              | rLength8:
+     // ex: .quad Lfoo + N
+     *kind = pointer64;
+     return atomFromAddress(reloc.symbol, *(const little64_t *)fixupContent,
+                            target, addend);
+  case ARM64_RELOC_POINTER_TO_GOT              | rExtern | rLength8:
+    // ex: .quad _foo@GOT
+    *kind = pointer64ToGOT;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  case ARM64_RELOC_POINTER_TO_GOT     | rPcRel | rExtern | rLength4:
+    // ex: .long _foo@GOT - .
+
+    // If we are in an .eh_frame section, then the kind of the relocation should
+    // not be delta32ToGOT.  It may instead be unwindCIEToPersonalityFunction.
+    if (inAtom->contentType() == DefinedAtom::typeCFI)
+      *kind = unwindCIEToPersonalityFunction;
+    else
+      *kind = delta32ToGOT;
+
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return llvm::Error::success();
+  default:
+    return llvm::make_error<GenericError>("unsupported arm64 relocation type");
+  }
+}
+
+llvm::Error ArchHandler_arm64::getPairReferenceInfo(
+    const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
+    const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
+    bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress,
+    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+    const lld::Atom **target, Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
+         ARM64_RELOC_BRANCH26           | rPcRel | rExtern | rLength4):
+    // ex: bl _foo+8
+    *kind = branch26;
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = reloc1.symbol;
+    return llvm::Error::success();
+  case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
+         ARM64_RELOC_PAGE21             | rPcRel | rExtern | rLength4):
+    // ex: adrp x1, _foo@PAGE
+    *kind = page21;
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = reloc1.symbol;
+    return llvm::Error::success();
+  case ((ARM64_RELOC_ADDEND                                | rLength4) << 16 |
+         ARM64_RELOC_PAGEOFF12                   | rExtern | rLength4): {
+    // ex: ldr w0, [x1, _foo@PAGEOFF]
+    uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent;
+    *kind = offset12KindFromInstruction(cont32);
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = reloc1.symbol;
+    return llvm::Error::success();
+  }
+  case ((ARM64_RELOC_SUBTRACTOR                  | rExtern | rLength8) << 16 |
+         ARM64_RELOC_UNSIGNED                    | rExtern | rLength8):
+    // ex: .quad _foo - .
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+
+    // If we are in an .eh_frame section, then the kind of the relocation should
+    // not be delta64.  It may instead be unwindFDEToFunction.
+    if (inAtom->contentType() == DefinedAtom::typeCFI)
+      *kind = unwindFDEToFunction;
+    else
+      *kind = delta64;
+
+    // The offsets of the 2 relocations must match
+    if (reloc1.offset != reloc2.offset)
+      return llvm::make_error<GenericError>(
+                                    "paired relocs must have the same offset");
+    *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
+    return llvm::Error::success();
+  case ((ARM64_RELOC_SUBTRACTOR                  | rExtern | rLength4) << 16 |
+         ARM64_RELOC_UNSIGNED                    | rExtern | rLength4):
+    // ex: .quad _foo - .
+    *kind = delta32;
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
+    return llvm::Error::success();
+  default:
+    return llvm::make_error<GenericError>("unsupported arm64 relocation pair");
+  }
+}
+
+void ArchHandler_arm64::generateAtomContent(
+    const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+    FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+    llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+#ifndef NDEBUG
+  if (atom.begin() != atom.end()) {
+    DEBUG_WITH_TYPE("atom-content", llvm::dbgs()
+                    << "Applying fixups to atom:\n"
+                    << "   address="
+                    << llvm::format("    0x%09lX", &atom)
+                    << ", file=#"
+                    << atom.file().ordinal()
+                    << ", atom=#"
+                    << atom.ordinal()
+                    << ", name="
+                    << atom.name()
+                    << ", type="
+                    << atom.contentType()
+                    << "\n");
+  }
+#endif
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    bool targetUnnamed = target->name().empty();
+    uint64_t targetAddress = 0;
+    if (isa<DefinedAtom>(target))
+      targetAddress = findAddress(*target);
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
+                            targetAddress, atomAddress, targetUnnamed);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
+                      targetAddress, atomAddress, imageBaseAddress,
+                      findSectionAddress);
+    }
+  }
+}
+
+void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
+                                        uint64_t fixupAddress,
+                                        uint64_t targetAddress,
+                                        uint64_t inAtomAddress,
+                                        uint64_t imageBaseAddress,
+                                        FindAddressForAtom findSectionAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  int32_t displacement;
+  uint32_t instruction;
+  uint32_t value32;
+  uint32_t value64;
+  switch (static_cast<Arm64Kind>(ref.kindValue())) {
+  case branch26:
+    displacement = (targetAddress - fixupAddress) + ref.addend();
+    *loc32 = setDisplacementInBranch26(*loc32, displacement);
+    return;
+  case page21:
+  case gotPage21:
+  case tlvPage21:
+    displacement =
+        ((targetAddress + ref.addend()) & (-4096)) - (fixupAddress & (-4096));
+    *loc32 = setDisplacementInADRP(*loc32, displacement);
+    return;
+  case offset12:
+  case gotOffset12:
+  case tlvOffset12:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    *loc32 = setImm12(*loc32, displacement);
+    return;
+  case offset12scale2:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0x1) == 0) &&
+           "scaled imm12 not accessing 2-byte aligneds");
+    *loc32 = setImm12(*loc32, displacement >> 1);
+    return;
+  case offset12scale4:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0x3) == 0) &&
+           "scaled imm12 not accessing 4-byte aligned");
+    *loc32 = setImm12(*loc32, displacement >> 2);
+    return;
+  case offset12scale8:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0x7) == 0) &&
+           "scaled imm12 not accessing 8-byte aligned");
+    *loc32 = setImm12(*loc32, displacement >> 3);
+    return;
+  case offset12scale16:
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    assert(((displacement & 0xF) == 0) &&
+           "scaled imm12 not accessing 16-byte aligned");
+    *loc32 = setImm12(*loc32, displacement >> 4);
+    return;
+  case addOffset12:
+    instruction = *loc32;
+    assert(((instruction & 0xFFC00000) == 0xF9400000) &&
+           "GOT reloc is not an LDR instruction");
+    displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+    value32 = 0x91000000 | (instruction & 0x000003FF);
+    instruction = setImm12(value32, displacement);
+    *loc32 = instruction;
+    return;
+  case pointer64:
+  case pointer64ToGOT:
+    *loc64 = targetAddress + ref.addend();
+    return;
+  case delta64:
+  case unwindFDEToFunction:
+    *loc64 = (targetAddress - fixupAddress) + ref.addend();
+    return;
+  case delta32:
+  case delta32ToGOT:
+  case unwindCIEToPersonalityFunction:
+    *loc32 = (targetAddress - fixupAddress) + ref.addend();
+    return;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case lazyPointer:
+    // Do nothing
+    return;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    return;
+  case imageOffset:
+    *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
+    return;
+  case imageOffsetGot:
+    llvm_unreachable("imageOffsetGot should have been changed to imageOffset");
+    break;
+  case unwindInfoToEhFrame:
+    value64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+    assert(value64 < 0xffffffU && "offset in __eh_frame too large");
+    *loc32 = (*loc32 & 0xff000000U) | value64;
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("invalid arm64 Reference Kind");
+}
+
+void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
+                                              uint8_t *loc,
+                                              uint64_t fixupAddress,
+                                              uint64_t targetAddress,
+                                              uint64_t inAtomAddress,
+                                              bool targetUnnamed) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  switch (static_cast<Arm64Kind>(ref.kindValue())) {
+  case branch26:
+    *loc32 = setDisplacementInBranch26(*loc32, 0);
+    return;
+  case page21:
+  case gotPage21:
+  case tlvPage21:
+    *loc32 = setDisplacementInADRP(*loc32, 0);
+    return;
+  case offset12:
+  case offset12scale2:
+  case offset12scale4:
+  case offset12scale8:
+  case offset12scale16:
+  case gotOffset12:
+  case tlvOffset12:
+    *loc32 = setImm12(*loc32, 0);
+    return;
+  case pointer64:
+    if (targetUnnamed)
+      *loc64 = targetAddress + ref.addend();
+    else
+      *loc64 = ref.addend();
+    return;
+  case delta64:
+    *loc64 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case unwindFDEToFunction:
+    // We don't emit unwindFDEToFunction in -r mode as they are implicitly
+    // generated from the data in the __eh_frame section.  So here we need
+    // to use the targetAddress so that we can generate the full relocation
+    // when we parse again later.
+    *loc64 = targetAddress - fixupAddress;
+    return;
+  case delta32:
+    *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case negDelta32:
+    // We don't emit negDelta32 in -r mode as they are implicitly
+    // generated from the data in the __eh_frame section.  So here we need
+    // to use the targetAddress so that we can generate the full relocation
+    // when we parse again later.
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case pointer64ToGOT:
+    *loc64 = 0;
+    return;
+  case delta32ToGOT:
+    *loc32 = inAtomAddress - fixupAddress;
+    return;
+  case unwindCIEToPersonalityFunction:
+    // We don't emit unwindCIEToPersonalityFunction in -r mode as they are
+    // implicitly generated from the data in the __eh_frame section.  So here we
+    // need to use the targetAddress so that we can generate the full relocation
+    // when we parse again later.
+    *loc32 = targetAddress - fixupAddress;
+    return;
+  case addOffset12:
+    llvm_unreachable("lazy reference kind implies GOT pass was run");
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+  case imageOffset:
+  case imageOffsetGot:
+  case unwindInfoToEhFrame:
+    llvm_unreachable("fixup implies __unwind_info");
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown arm64 Reference Kind");
+}
+
+void ArchHandler_arm64::appendSectionRelocations(
+    const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref,
+    FindSymbolIndexForAtom symbolIndexForAtom,
+    FindSectionIndexForAtom sectionIndexForAtom,
+    FindAddressForAtom addressForAtom, normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::AArch64);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  switch (static_cast<Arm64Kind>(ref.kindValue())) {
+  case branch26:
+    if (ref.addend()) {
+      appendReloc(relocs, sectionOffset, ref.addend(), 0,
+                  ARM64_RELOC_ADDEND | rLength4);
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
+     } else {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
+    }
+    return;
+  case page21:
+    if (ref.addend()) {
+      appendReloc(relocs, sectionOffset, ref.addend(), 0,
+                  ARM64_RELOC_ADDEND | rLength4);
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
+     } else {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
+    }
+    return;
+  case offset12:
+  case offset12scale2:
+  case offset12scale4:
+  case offset12scale8:
+  case offset12scale16:
+    if (ref.addend()) {
+      appendReloc(relocs, sectionOffset, ref.addend(), 0,
+                  ARM64_RELOC_ADDEND | rLength4);
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGEOFF12  | rExtern | rLength4);
+     } else {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
+    }
+    return;
+  case gotPage21:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
+    return;
+  case gotOffset12:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4);
+    return;
+  case tlvPage21:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
+    return;
+  case tlvOffset12:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4);
+    return;
+  case pointer64:
+    if (ref.target()->name().empty())
+      appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_UNSIGNED           | rLength8);
+    else
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_UNSIGNED | rExtern | rLength8);
+    return;
+  case delta64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                ARM64_RELOC_SUBTRACTOR | rExtern | rLength8);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                ARM64_RELOC_UNSIGNED  | rExtern | rLength8);
+    return;
+  case delta32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                ARM64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                ARM64_RELOC_UNSIGNED   | rExtern | rLength4 );
+    return;
+  case pointer64ToGOT:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8);
+    return;
+  case delta32ToGOT:
+    assert(ref.addend() == 0);
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4);
+    return;
+  case addOffset12:
+    llvm_unreachable("lazy reference kind implies GOT pass was run");
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+  case imageOffset:
+  case imageOffsetGot:
+    llvm_unreachable("deltas from mach_header can only be in final images");
+  case unwindCIEToPersonalityFunction:
+  case unwindFDEToFunction:
+  case unwindInfoToEhFrame:
+  case negDelta32:
+    // Do nothing.
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown arm64 Reference Kind");
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm64() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm64());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
new file mode 100644 (file)
index 0000000..2272bff
--- /dev/null
@@ -0,0 +1,640 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+
+using llvm::support::little16_t;
+using llvm::support::little32_t;
+
+class ArchHandler_x86 : public ArchHandler {
+public:
+  ArchHandler_x86() = default;
+  ~ArchHandler_x86() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+  bool isCallSite(const Reference &) override;
+  bool isNonCallBranch(const Reference &) override {
+    return false;
+  }
+
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+
+  bool needsCompactUnwind() override {
+    return false;
+  }
+
+  Reference::KindValue imageOffsetKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return negDelta32;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override{
+    return delta32;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return invalid;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return invalid;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    return 0x04000000U;
+  }
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool swap,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBaseAddress,
+                    llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom symbolIndexForAtom,
+                                FindSectionIndexForAtom sectionIndexForAtom,
+                                FindAddressForAtom addressForAtom,
+                                normalized::Relocations &relocs) override;
+
+  bool isDataInCodeTransition(Reference::KindValue refKind) override {
+    return refKind == modeCode || refKind == modeData;
+  }
+
+  Reference::KindValue dataInCodeTransitionStart(
+                                        const MachODefinedAtom &atom) override {
+    return modeData;
+  }
+
+  Reference::KindValue dataInCodeTransitionEnd(
+                                        const MachODefinedAtom &atom) override {
+    return modeCode;
+  }
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfo;
+
+  enum X86Kind : Reference::KindValue {
+    invalid,               /// for error condition
+
+    modeCode,              /// Content starting at this offset is code.
+    modeData,              /// Content starting at this offset is data.
+
+    // Kinds found in mach-o .o files:
+    branch32,              /// ex: call _foo
+    branch16,              /// ex: callw _foo
+    abs32,                 /// ex: movl _foo, %eax
+    funcRel32,             /// ex: movl _foo-L1(%eax), %eax
+    pointer32,             /// ex: .long _foo
+    delta32,               /// ex: .long _foo - .
+    negDelta32,            /// ex: .long . - _foo
+
+    // Kinds introduced by Passes:
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+  };
+
+  static bool useExternalRelocationTo(const Atom &target);
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress,
+                             uint64_t targetAddress,
+                             uint64_t inAtomAddress);
+};
+
+//===----------------------------------------------------------------------===//
+//  ArchHandler_x86
+//===----------------------------------------------------------------------===//
+
+const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid),
+  LLD_KIND_STRING_ENTRY(modeCode),
+  LLD_KIND_STRING_ENTRY(modeData),
+  LLD_KIND_STRING_ENTRY(branch32),
+  LLD_KIND_STRING_ENTRY(branch16),
+  LLD_KIND_STRING_ENTRY(abs32),
+  LLD_KIND_STRING_ENTRY(funcRel32),
+  LLD_KIND_STRING_ENTRY(pointer32),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(negDelta32),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references
+  { Reference::KindArch::x86, pointer32, 0, 0 },
+  { Reference::KindArch::x86, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::x86, pointer32, 0, 0 },
+
+  // x86 code alignment
+  1,
+
+  // Stub size and code
+  6,
+  { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
+  { Reference::KindArch::x86, abs32, 2, 0 },
+  { false, 0, 0, 0 },
+
+  // Stub Helper size and code
+  10,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $lazy-info-offset
+    0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
+  { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
+  { Reference::KindArch::x86, branch32, 6, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeNonLazyPointer,
+
+  // Stub Helper-Common size and code
+  12,
+  // Stub helper alignment
+  2,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $dyld_ImageLoaderCache
+    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *_fast_lazy_bind
+    0x90 },                                     // nop
+  { Reference::KindArch::x86, abs32, 1, 0 },
+  { false, 0, 0, 0 },
+  { Reference::KindArch::x86, abs32, 7, 0 },
+  { false, 0, 0, 0 }
+};
+
+bool ArchHandler_x86::isCallSite(const Reference &ref) {
+  return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86::isPointer(const Reference &ref) {
+  return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
+  if (!reloc.scattered)
+    return false;
+  return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
+         (reloc.type == GENERIC_RELOC_SECTDIFF);
+}
+
+llvm::Error
+ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
+                                  const DefinedAtom *inAtom,
+                                  uint32_t offsetInAtom,
+                                  uint64_t fixupAddress, bool swap,
+                                  FindAtomBySectionAndAddress atomFromAddress,
+                                  FindAtomBySymbolIndex atomFromSymbolIndex,
+                                  Reference::KindValue *kind,
+                                  const lld::Atom **target,
+                                  Reference::Addend *addend) {
+  DefinedAtom::ContentPermissions perms;
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  switch (relocPattern(reloc)) {
+  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
+    // ex: call _foo (and _foo undefined)
+    *kind = branch32;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
+    // ex: call _foo (and _foo defined)
+    *kind = branch32;
+    targetAddress =
+        fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
+    // ex: call _foo+n (and _foo defined)
+    *kind = branch32;
+    targetAddress =
+        fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend = targetAddress - reloc.value;
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
+    // ex: callw _foo (and _foo undefined)
+    *kind = branch16;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
+    // ex: callw _foo (and _foo defined)
+    *kind = branch16;
+    targetAddress =
+        fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
+    // ex: callw _foo+n (and _foo defined)
+    *kind = branch16;
+    targetAddress =
+        fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend = targetAddress - reloc.value;
+    break;
+  case GENERIC_RELOC_VANILLA | rExtern | rLength4:
+    // ex: movl        _foo, %eax   (and _foo undefined)
+    // ex: .long _foo        (and _foo undefined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const ulittle32_t *)fixupContent;
+    break;
+  case GENERIC_RELOC_VANILLA | rLength4:
+    // ex: movl        _foo, %eax   (and _foo defined)
+    // ex: .long _foo        (and _foo defined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    targetAddress = *(const ulittle32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rScattered | rLength4:
+    // ex: .long _foo+n      (and _foo defined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend = *(const ulittle32_t *)fixupContent - reloc.value;
+    break;
+  default:
+    return llvm::make_error<GenericError>("unsupported i386 relocation type");
+  }
+  return llvm::Error::success();
+}
+
+llvm::Error
+ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                      const normalized::Relocation &reloc2,
+                                      const DefinedAtom *inAtom,
+                                      uint32_t offsetInAtom,
+                                      uint64_t fixupAddress, bool swap,
+                                      bool scatterable,
+                                      FindAtomBySectionAndAddress atomFromAddr,
+                                      FindAtomBySymbolIndex atomFromSymbolIndex,
+                                      Reference::KindValue *kind,
+                                      const lld::Atom **target,
+                                      Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  DefinedAtom::ContentPermissions perms = inAtom->permissions();
+  uint32_t fromAddress;
+  uint32_t toAddress;
+  uint32_t value;
+  const lld::Atom *fromTarget;
+  Reference::Addend offsetInTo;
+  Reference::Addend offsetInFrom;
+  switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
+         GENERIC_RELOC_PAIR | rScattered | rLength4):
+  case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+         GENERIC_RELOC_PAIR | rScattered | rLength4):
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    value = *(const little32_t *)fixupContent;
+    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+      return ec;
+    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+      return ec;
+    if (fromTarget != inAtom) {
+      if (*target != inAtom)
+        return llvm::make_error<GenericError>(
+            "SECTDIFF relocation where neither target is in atom");
+      *kind = negDelta32;
+      *addend = toAddress - value - fromAddress;
+      *target = fromTarget;
+    } else {
+      if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
+        // SECTDIFF relocations are used in i386 codegen where the function
+        // prolog does a CALL to the next instruction which POPs the return
+        // address into EBX which becomes the pic-base register.  The POP
+        // instruction is label the used for the subtrahend in expressions.
+        // The funcRel32 kind represents the 32-bit delta to some symbol from
+        // the start of the function (atom) containing the funcRel32.
+        *kind = funcRel32;
+        uint32_t ta = fromAddress + value - toAddress;
+        *addend = ta - offsetInFrom;
+      } else {
+        *kind = delta32;
+        *addend = fromAddress + value - toAddress;
+      }
+    }
+    return llvm::Error::success();
+    break;
+  default:
+    return llvm::make_error<GenericError>("unsupported i386 relocation type");
+  }
+}
+
+void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
+                                          bool relocatable,
+                                          FindAddressForAtom findAddress,
+                                          FindAddressForAtom findSectionAddress,
+                                          uint64_t imageBaseAddress,
+                            llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    uint64_t targetAddress = 0;
+    if (isa<DefinedAtom>(target))
+      targetAddress = findAddress(*target);
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+                                        fixupAddress, targetAddress,
+                                        atomAddress);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset],
+                                  fixupAddress, targetAddress,
+                                  atomAddress);
+    }
+  }
+}
+
+void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
+                                      uint64_t fixupAddress,
+                                      uint64_t targetAddress,
+                                      uint64_t inAtomAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  switch (static_cast<X86Kind>(ref.kindValue())) {
+  case branch32:
+    *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    break;
+  case branch16:
+    *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
+    break;
+  case pointer32:
+  case abs32:
+    *loc32 = targetAddress + ref.addend();
+    break;
+  case funcRel32:
+    *loc32 = targetAddress - inAtomAddress + ref.addend();
+    break;
+  case delta32:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    break;
+  case modeCode:
+  case modeData:
+  case lazyPointer:
+    // do nothing
+    break;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    break;
+  case invalid:
+    llvm_unreachable("invalid x86 Reference Kind");
+    break;
+  }
+}
+
+void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
+                                               uint8_t *loc,
+                                               uint64_t fixupAddress,
+                                               uint64_t targetAddress,
+                                               uint64_t inAtomAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86);
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  switch (static_cast<X86Kind>(ref.kindValue())) {
+  case branch32:
+    if (useExternalReloc)
+      *loc32 = ref.addend() - (fixupAddress + 4);
+    else
+      *loc32  =(targetAddress - (fixupAddress+4)) + ref.addend();
+    break;
+  case branch16:
+    if (useExternalReloc)
+      *loc16 = ref.addend() - (fixupAddress + 2);
+    else
+      *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
+    break;
+  case pointer32:
+  case abs32:
+    *loc32 = targetAddress + ref.addend();
+    break;
+  case funcRel32:
+    *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
+    break;
+  case delta32:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    break;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    break;
+  case modeCode:
+  case modeData:
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  case invalid:
+    llvm_unreachable("invalid x86 Reference Kind");
+    break;
+  }
+}
+
+bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
+  // Undefined symbols are referenced via external relocations.
+  if (isa<UndefinedAtom>(&target))
+    return true;
+  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+     switch (defAtom->merge()) {
+     case DefinedAtom::mergeAsTentative:
+       // Tentative definitions are referenced via external relocations.
+       return true;
+     case DefinedAtom::mergeAsWeak:
+     case DefinedAtom::mergeAsWeakAndAddressUsed:
+       // Global weak-defs are referenced via external relocations.
+       return (defAtom->scope() == DefinedAtom::scopeGlobal);
+     default:
+       break;
+    }
+  }
+  // Everything else is reference via an internal relocation.
+  return false;
+}
+
+void ArchHandler_x86::appendSectionRelocations(
+                                   const DefinedAtom &atom,
+                                   uint64_t atomSectionOffset,
+                                   const Reference &ref,
+                                   FindSymbolIndexForAtom symbolIndexForAtom,
+                                   FindSectionIndexForAtom sectionIndexForAtom,
+                                   FindAddressForAtom addressForAtom,
+                                   normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  bool useExternalReloc = useExternalRelocationTo(*ref.target());
+  switch (static_cast<X86Kind>(ref.kindValue())) {
+  case modeCode:
+  case modeData:
+    break;
+  case branch32:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  GENERIC_RELOC_VANILLA | rExtern    | rPcRel | rLength4);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  GENERIC_RELOC_VANILLA | rScattered | rPcRel |  rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  GENERIC_RELOC_VANILLA |              rPcRel | rLength4);
+    }
+    break;
+  case branch16:
+    if (useExternalReloc) {
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                  GENERIC_RELOC_VANILLA | rExtern    | rPcRel | rLength2);
+    } else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                  GENERIC_RELOC_VANILLA | rScattered | rPcRel |  rLength2);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+                  GENERIC_RELOC_VANILLA |              rPcRel | rLength2);
+    }
+    break;
+  case pointer32:
+  case abs32:
+    if (useExternalReloc)
+      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()),  0,
+                GENERIC_RELOC_VANILLA |    rExtern     |  rLength4);
+    else {
+      if (ref.addend() != 0)
+        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+                GENERIC_RELOC_VANILLA |    rScattered  |  rLength4);
+      else
+        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                GENERIC_RELOC_VANILLA |                   rLength4);
+    }
+    break;
+  case funcRel32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
+              GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
+    break;
+  case delta32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+                                                           ref.offsetInAtom(),
+              GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
+    break;
+  case negDelta32:
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+                                                           ref.offsetInAtom(),
+              GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
+    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+              GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+    break;
+  case invalid:
+    llvm_unreachable("unknown x86 Reference Kind");
+    break;
+  }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
new file mode 100644 (file)
index 0000000..d687ca5
--- /dev/null
@@ -0,0 +1,861 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86_64.cpp ------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::ulittle64_t;
+
+using llvm::support::little32_t;
+using llvm::support::little64_t;
+
+class ArchHandler_x86_64 : public ArchHandler {
+public:
+  ArchHandler_x86_64() = default;
+  ~ArchHandler_x86_64() override = default;
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override {
+    return Reference::KindArch::x86_64;
+  }
+
+  /// Used by GOTPass to locate GOT References
+  bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+    if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+      return false;
+    assert(ref.kindArch() == Reference::KindArch::x86_64);
+    switch (ref.kindValue()) {
+    case ripRel32GotLoad:
+      canBypassGOT = true;
+      return true;
+    case ripRel32Got:
+      canBypassGOT = false;
+      return true;
+    case imageOffsetGot:
+      canBypassGOT = false;
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  bool isTLVAccess(const Reference &ref) const override {
+    assert(ref.kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref.kindArch() == Reference::KindArch::x86_64);
+    return ref.kindValue() == ripRel32Tlv;
+  }
+
+  void updateReferenceToTLV(const Reference *ref) override {
+    assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref->kindArch() == Reference::KindArch::x86_64);
+    assert(ref->kindValue() == ripRel32Tlv);
+    const_cast<Reference*>(ref)->setKindValue(ripRel32);
+  }
+
+  /// Used by GOTPass to update GOT References
+  void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+    assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref->kindArch() == Reference::KindArch::x86_64);
+
+    switch (ref->kindValue()) {
+    case ripRel32Got:
+      assert(targetNowGOT && "target must be GOT");
+    case ripRel32GotLoad:
+      const_cast<Reference *>(ref)
+        ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea);
+      break;
+    case imageOffsetGot:
+      const_cast<Reference *>(ref)->setKindValue(imageOffset);
+      break;
+    default:
+      llvm_unreachable("unknown GOT reference kind");
+    }
+  }
+
+  bool needsCompactUnwind() override {
+    return true;
+  }
+
+  Reference::KindValue imageOffsetKind() override {
+    return imageOffset;
+  }
+
+  Reference::KindValue imageOffsetKindIndirect() override {
+    return imageOffsetGot;
+  }
+
+  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+    return ripRel32Got;
+  }
+
+  Reference::KindValue unwindRefToCIEKind() override {
+    return negDelta32;
+  }
+
+  Reference::KindValue unwindRefToFunctionKind() override{
+    return unwindFDEToFunction;
+  }
+
+  Reference::KindValue unwindRefToEhFrameKind() override {
+    return unwindInfoToEhFrame;
+  }
+
+  Reference::KindValue pointerKind() override {
+    return pointer64;
+  }
+
+  uint32_t dwarfCompactUnwindType() override {
+    return 0x04000000U;
+  }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+
+  bool isNonCallBranch(const Reference &) override {
+    return false;
+  }
+
+  bool isCallSite(const Reference &) override;
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+
+  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+                               const DefinedAtom *inAtom,
+                               uint32_t offsetInAtom,
+                               uint64_t fixupAddress, bool swap,
+                               FindAtomBySectionAndAddress atomFromAddress,
+                               FindAtomBySymbolIndex atomFromSymbolIndex,
+                               Reference::KindValue *kind,
+                               const lld::Atom **target,
+                               Reference::Addend *addend) override;
+  llvm::Error
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap, bool scatterable,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
+    return (atom->contentType() == DefinedAtom::typeCString);
+  }
+
+  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+                           FindAddressForAtom findAddress,
+                           FindAddressForAtom findSectionAddress,
+                           uint64_t imageBase,
+                    llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+  void appendSectionRelocations(const DefinedAtom &atom,
+                                uint64_t atomSectionOffset,
+                                const Reference &ref,
+                                FindSymbolIndexForAtom symbolIndexForAtom,
+                                FindSectionIndexForAtom sectionIndexForAtom,
+                                FindAddressForAtom addressForAtom,
+                                normalized::Relocations &relocs) override;
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfo;
+
+  enum X86_64Kind: Reference::KindValue {
+    invalid,               /// for error condition
+
+    // Kinds found in mach-o .o files:
+    branch32,              /// ex: call _foo
+    ripRel32,              /// ex: movq _foo(%rip), %rax
+    ripRel32Minus1,        /// ex: movb $0x12, _foo(%rip)
+    ripRel32Minus2,        /// ex: movw $0x1234, _foo(%rip)
+    ripRel32Minus4,        /// ex: movl $0x12345678, _foo(%rip)
+    ripRel32Anon,          /// ex: movq L1(%rip), %rax
+    ripRel32Minus1Anon,    /// ex: movb $0x12, L1(%rip)
+    ripRel32Minus2Anon,    /// ex: movw $0x1234, L1(%rip)
+    ripRel32Minus4Anon,    /// ex: movw $0x12345678, L1(%rip)
+    ripRel32GotLoad,       /// ex: movq  _foo@GOTPCREL(%rip), %rax
+    ripRel32Got,           /// ex: pushq _foo@GOTPCREL(%rip)
+    ripRel32Tlv,           /// ex: movq  _foo@TLVP(%rip), %rdi
+    pointer64,             /// ex: .quad _foo
+    pointer64Anon,         /// ex: .quad L1
+    delta64,               /// ex: .quad _foo - .
+    delta32,               /// ex: .long _foo - .
+    delta64Anon,           /// ex: .quad L1 - .
+    delta32Anon,           /// ex: .long L1 - .
+    negDelta64,            /// ex: .quad . - _foo
+    negDelta32,            /// ex: .long . - _foo
+
+    // Kinds introduced by Passes:
+    ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so
+                           ///  "movq  _foo@GOTPCREL(%rip), %rax" can be changed
+                           /// to "leaq _foo(%rip), %rax
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+
+    imageOffset,           /// Location contains offset of atom in final image
+    imageOffsetGot,        /// Location contains offset of GOT entry for atom in
+                           /// final image (typically personality function).
+    unwindFDEToFunction,   /// Nearly delta64, but cannot be rematerialized in
+                           /// relocatable object (yay for implicit contracts!).
+    unwindInfoToEhFrame,   /// Fix low 24 bits of compact unwind encoding to
+                           /// refer to __eh_frame entry.
+    tlvInitSectionOffset   /// Location contains offset tlv init-value atom
+                           /// within the __thread_data section.
+  };
+
+  Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
+
+  void applyFixupFinal(const Reference &ref, uint8_t *location,
+                       uint64_t fixupAddress, uint64_t targetAddress,
+                       uint64_t inAtomAddress, uint64_t imageBaseAddress,
+                       FindAddressForAtom findSectionAddress);
+
+  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+                             uint64_t fixupAddress,
+                             uint64_t targetAddress,
+                             uint64_t inAtomAddress);
+};
+
+const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
+  LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+  LLD_KIND_STRING_ENTRY(ripRel32Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon),
+  LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+  LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+  LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
+  LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
+  LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
+  LLD_KIND_STRING_ENTRY(negDelta64),
+  LLD_KIND_STRING_ENTRY(negDelta32),
+  LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
+  LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
+  LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+  LLD_KIND_STRING_ENTRY(tlvInitSectionOffset),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references
+  { Reference::KindArch::x86_64, pointer64, 0, 0 },
+  { Reference::KindArch::x86_64, lazyPointer, 0, 0 },
+
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::x86_64, pointer64, 0, 0 },
+
+  // x86_64 code alignment 2^1
+  1,
+
+  // Stub size and code
+  6,
+  { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
+  { Reference::KindArch::x86_64, ripRel32, 2, 0 },
+  { false, 0, 0, 0 },
+
+  // Stub Helper size and code
+  10,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushq $lazy-info-offset
+    0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
+  { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
+  { Reference::KindArch::x86_64, branch32, 6, 0 },
+
+  // Stub helper image cache content type
+  DefinedAtom::typeNonLazyPointer,
+
+  // Stub Helper-Common size and code
+  16,
+  // Stub helper alignment
+  2,
+  { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00,   // leaq cache(%rip),%r11
+    0x41, 0x53,                                 // push %r11
+    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *binder(%rip)
+    0x90 },                                     // nop
+  { Reference::KindArch::x86_64, ripRel32, 3, 0 },
+  { false, 0, 0, 0 },
+  { Reference::KindArch::x86_64, ripRel32, 11, 0 },
+  { false, 0, 0, 0 }
+
+};
+
+bool ArchHandler_x86_64::isCallSite(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86_64::isPointer(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  Reference::KindValue kind = ref.kindValue();
+  return (kind == pointer64 || kind == pointer64Anon);
+}
+
+bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) {
+  return (reloc.type == X86_64_RELOC_SUBTRACTOR);
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
+  switch(relocPattern(reloc)) {
+  case X86_64_RELOC_BRANCH   | rPcRel | rExtern | rLength4:
+    return branch32;
+  case X86_64_RELOC_SIGNED   | rPcRel | rExtern | rLength4:
+    return ripRel32;
+  case X86_64_RELOC_SIGNED   | rPcRel |           rLength4:
+    return ripRel32Anon;
+  case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus1;
+  case X86_64_RELOC_SIGNED_1 | rPcRel |           rLength4:
+    return ripRel32Minus1Anon;
+  case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus2;
+  case X86_64_RELOC_SIGNED_2 | rPcRel |           rLength4:
+    return ripRel32Minus2Anon;
+  case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus4;
+  case X86_64_RELOC_SIGNED_4 | rPcRel |           rLength4:
+    return ripRel32Minus4Anon;
+  case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
+    return ripRel32GotLoad;
+  case X86_64_RELOC_GOT      | rPcRel | rExtern | rLength4:
+    return ripRel32Got;
+  case X86_64_RELOC_TLV      | rPcRel | rExtern | rLength4:
+    return ripRel32Tlv;
+  case X86_64_RELOC_UNSIGNED          | rExtern | rLength8:
+    return pointer64;
+  case X86_64_RELOC_UNSIGNED                    | rLength8:
+    return pointer64Anon;
+  default:
+    return invalid;
+  }
+}
+
+llvm::Error
+ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
+                                    const DefinedAtom *inAtom,
+                                    uint32_t offsetInAtom,
+                                    uint64_t fixupAddress, bool swap,
+                                    FindAtomBySectionAndAddress atomFromAddress,
+                                    FindAtomBySymbolIndex atomFromSymbolIndex,
+                                    Reference::KindValue *kind,
+                                    const lld::Atom **target,
+                                    Reference::Addend *addend) {
+  *kind = kindFromReloc(reloc);
+  if (*kind == invalid)
+    return llvm::make_error<GenericError>("unknown type");
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  switch (*kind) {
+  case branch32:
+  case ripRel32:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const little32_t *)fixupContent;
+    return llvm::Error::success();
+  case ripRel32Minus1:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + 1;
+    return llvm::Error::success();
+  case ripRel32Minus2:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + 2;
+    return llvm::Error::success();
+  case ripRel32Minus4:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = (int32_t)*(const little32_t *)fixupContent + 4;
+    return llvm::Error::success();
+  case ripRel32Anon:
+    targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32Minus1Anon:
+    targetAddress = fixupAddress + 5 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32Minus2Anon:
+    targetAddress = fixupAddress + 6 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32Minus4Anon:
+    targetAddress = fixupAddress + 8 + *(const little32_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32GotLoad:
+  case ripRel32Got:
+  case ripRel32Tlv:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = *(const little32_t *)fixupContent;
+    return llvm::Error::success();
+  case tlvInitSectionOffset:
+  case pointer64:
+    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // If this is the 3rd pointer of a tlv-thunk (i.e. the pointer to the TLV's
+    // initial value) we need to handle it specially.
+    if (inAtom->contentType() == DefinedAtom::typeThunkTLV &&
+        offsetInAtom == 16) {
+      *kind = tlvInitSectionOffset;
+      assert(*addend == 0 && "TLV-init has non-zero addend?");
+    } else
+      *addend = *(const little64_t *)fixupContent;
+    return llvm::Error::success();
+  case pointer64Anon:
+    targetAddress = *(const little64_t *)fixupContent;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  default:
+    llvm_unreachable("bad reloc kind");
+  }
+}
+
+llvm::Error
+ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                   const normalized::Relocation &reloc2,
+                                   const DefinedAtom *inAtom,
+                                   uint32_t offsetInAtom,
+                                   uint64_t fixupAddress, bool swap,
+                                   bool scatterable,
+                                   FindAtomBySectionAndAddress atomFromAddress,
+                                   FindAtomBySymbolIndex atomFromSymbolIndex,
+                                   Reference::KindValue *kind,
+                                   const lld::Atom **target,
+                                   Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  const lld::Atom *fromTarget;
+  if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+    return ec;
+
+  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+        X86_64_RELOC_UNSIGNED    | rExtern | rLength8): {
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent;
+    if (inAtom == fromTarget) {
+      if (inAtom->contentType() == DefinedAtom::typeCFI)
+        *kind = unwindFDEToFunction;
+      else
+        *kind = delta64;
+      *addend = encodedAddend + offsetInAtom;
+    } else if (inAtom == *target) {
+      *kind = negDelta64;
+      *addend = encodedAddend - offsetInAtom;
+      *target = fromTarget;
+    } else
+      return llvm::make_error<GenericError>("Invalid pointer diff");
+    return llvm::Error::success();
+  }
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+        X86_64_RELOC_UNSIGNED    | rExtern | rLength4): {
+    if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent;
+    if (inAtom == fromTarget) {
+      *kind = delta32;
+      *addend = encodedAddend + offsetInAtom;
+    } else if (inAtom == *target) {
+      *kind = negDelta32;
+      *addend = encodedAddend - offsetInAtom;
+      *target = fromTarget;
+    } else
+      return llvm::make_error<GenericError>("Invalid pointer diff");
+    return llvm::Error::success();
+  }
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+        X86_64_RELOC_UNSIGNED              | rLength8):
+    if (fromTarget != inAtom)
+      return llvm::make_error<GenericError>("pointer diff not in base atom");
+    *kind = delta64Anon;
+    targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent;
+    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+        X86_64_RELOC_UNSIGNED              | rLength4):
+    if (fromTarget != inAtom)
+      return llvm::make_error<GenericError>("pointer diff not in base atom");
+    *kind = delta32Anon;
+    targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent;
+    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+  default:
+    return llvm::make_error<GenericError>("unknown pair");
+  }
+}
+
+void ArchHandler_x86_64::generateAtomContent(
+    const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+    FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+    llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+  // Copy raw bytes.
+  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+            atomContentBuffer.begin());
+  // Apply fix-ups.
+  for (const Reference *ref : atom) {
+    uint32_t offset = ref->offsetInAtom();
+    const Atom *target = ref->target();
+    uint64_t targetAddress = 0;
+    if (isa<DefinedAtom>(target))
+      targetAddress = findAddress(*target);
+    uint64_t atomAddress = findAddress(atom);
+    uint64_t fixupAddress = atomAddress + offset;
+    if (relocatable) {
+      applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+                                        fixupAddress, targetAddress,
+                                        atomAddress);
+    } else {
+      applyFixupFinal(*ref, &atomContentBuffer[offset],
+                      fixupAddress, targetAddress,
+                      atomAddress, imageBaseAddress, findSectionAddress);
+    }
+  }
+}
+
+void ArchHandler_x86_64::applyFixupFinal(
+    const Reference &ref, uint8_t *loc, uint64_t fixupAddress,
+    uint64_t targetAddress, uint64_t inAtomAddress, uint64_t imageBaseAddress,
+    FindAddressForAtom findSectionAddress) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  switch (static_cast<X86_64Kind>(ref.kindValue())) {
+  case branch32:
+  case ripRel32:
+  case ripRel32Anon:
+  case ripRel32Got:
+  case ripRel32GotLoad:
+  case ripRel32Tlv:
+    *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
+    return;
+  case pointer64:
+  case pointer64Anon:
+    *loc64 = targetAddress + ref.addend();
+    return;
+  case tlvInitSectionOffset:
+    *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+    return;
+  case ripRel32Minus1:
+  case ripRel32Minus1Anon:
+    *loc32 = targetAddress - (fixupAddress + 5) + ref.addend();
+    return;
+  case ripRel32Minus2:
+  case ripRel32Minus2Anon:
+    *loc32 = targetAddress - (fixupAddress + 6) + ref.addend();
+    return;
+  case ripRel32Minus4:
+  case ripRel32Minus4Anon:
+    *loc32 = targetAddress - (fixupAddress + 8) + ref.addend();
+    return;
+  case delta32:
+  case delta32Anon:
+    *loc32 = targetAddress - fixupAddress + ref.addend();
+    return;
+  case delta64:
+  case delta64Anon:
+  case unwindFDEToFunction:
+    *loc64 = targetAddress - fixupAddress + ref.addend();
+    return;
+  case ripRel32GotLoadNowLea:
+    // Change MOVQ to LEA
+    assert(loc[-2] == 0x8B);
+    loc[-2] = 0x8D;
+    *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
+    return;
+  case negDelta64:
+    *loc64 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case negDelta32:
+    *loc32 = fixupAddress - targetAddress + ref.addend();
+    return;
+  case lazyPointer:
+    // Do nothing
+    return;
+  case lazyImmediateLocation:
+    *loc32 = ref.addend();
+    return;
+  case imageOffset:
+  case imageOffsetGot:
+    *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
+    return;
+  case unwindInfoToEhFrame: {
+    uint64_t val = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+    assert(val < 0xffffffU && "offset in __eh_frame too large");
+    *loc32 = (*loc32 & 0xff000000U) | val;
+    return;
+  }
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("invalid x86_64 Reference Kind");
+}
+
+void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
+                                               uint8_t *loc,
+                                               uint64_t fixupAddress,
+                                               uint64_t targetAddress,
+                                               uint64_t inAtomAddress)  {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+  ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+  switch (static_cast<X86_64Kind>(ref.kindValue())) {
+  case branch32:
+  case ripRel32:
+  case ripRel32Got:
+  case ripRel32GotLoad:
+  case ripRel32Tlv:
+    *loc32 = ref.addend();
+    return;
+  case ripRel32Anon:
+    *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
+    return;
+  case tlvInitSectionOffset:
+  case pointer64:
+    *loc64 = ref.addend();
+    return;
+  case pointer64Anon:
+    *loc64 = targetAddress + ref.addend();
+    return;
+  case ripRel32Minus1:
+    *loc32 = ref.addend() - 1;
+    return;
+  case ripRel32Minus1Anon:
+    *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend();
+    return;
+  case ripRel32Minus2:
+    *loc32 = ref.addend() - 2;
+    return;
+  case ripRel32Minus2Anon:
+    *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend();
+    return;
+  case ripRel32Minus4:
+    *loc32 = ref.addend() - 4;
+    return;
+  case ripRel32Minus4Anon:
+    *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend();
+    return;
+  case delta32:
+    *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case delta32Anon:
+    // The value we write here should be the the delta to the target
+    // after taking in to account the difference from the fixup back to the
+    // last defined label
+    // ie, if we have:
+    // _base: ...
+    // Lfixup: .quad Ltarget - .
+    // ...
+    // Ltarget:
+    //
+    // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
+    *loc32 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
+    return;
+  case delta64:
+    *loc64 = ref.addend() + inAtomAddress - fixupAddress;
+    return;
+  case delta64Anon:
+    // The value we write here should be the the delta to the target
+    // after taking in to account the difference from the fixup back to the
+    // last defined label
+    // ie, if we have:
+    // _base: ...
+    // Lfixup: .quad Ltarget - .
+    // ...
+    // Ltarget:
+    //
+    // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
+    *loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
+    return;
+  case negDelta64:
+    *loc64 = ref.addend() + fixupAddress - inAtomAddress;
+    return;
+  case negDelta32:
+    *loc32 = ref.addend() + fixupAddress - inAtomAddress;
+    return;
+  case ripRel32GotLoadNowLea:
+    llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+    return;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+    return;
+  case imageOffset:
+  case imageOffsetGot:
+  case unwindInfoToEhFrame:
+    llvm_unreachable("fixup implies __unwind_info");
+    return;
+  case unwindFDEToFunction:
+    // Do nothing for now
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown x86_64 Reference Kind");
+}
+
+void ArchHandler_x86_64::appendSectionRelocations(
+                                   const DefinedAtom &atom,
+                                   uint64_t atomSectionOffset,
+                                   const Reference &ref,
+                                   FindSymbolIndexForAtom symbolIndexForAtom,
+                                   FindSectionIndexForAtom sectionIndexForAtom,
+                                   FindAddressForAtom addressForAtom,
+                                   normalized::Relocations &relocs) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+  switch (static_cast<X86_64Kind>(ref.kindValue())) {
+  case branch32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4);
+    return;
+  case ripRel32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED | rPcRel           | rLength4 );
+    return;
+  case ripRel32Got:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32GotLoad:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Tlv:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 );
+    return;
+  case tlvInitSectionOffset:
+  case pointer64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED  | rExtern | rLength8);
+    return;
+  case pointer64Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED | rLength8);
+    return;
+  case ripRel32Minus1:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Minus1Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_1 | rPcRel           | rLength4 );
+    return;
+  case ripRel32Minus2:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Minus2Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_2 | rPcRel           | rLength4 );
+    return;
+  case ripRel32Minus4:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 );
+    return;
+  case ripRel32Minus4Anon:
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SIGNED_4 | rPcRel           | rLength4 );
+    return;
+  case delta32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength4 );
+    return;
+  case delta32Anon:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED             | rLength4 );
+    return;
+  case delta64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength8 );
+    return;
+  case delta64Anon:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+    appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_UNSIGNED             | rLength8 );
+    return;
+  case unwindFDEToFunction:
+  case unwindInfoToEhFrame:
+    return;
+  case negDelta32:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength4 );
+    return;
+  case negDelta64:
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+                X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+    appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+                X86_64_RELOC_UNSIGNED   | rExtern | rLength8 );
+    return;
+  case ripRel32GotLoadNowLea:
+    llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+    return;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    llvm_unreachable("lazy reference kind implies Stubs pass was run");
+    return;
+  case imageOffset:
+  case imageOffsetGot:
+    llvm_unreachable("__unwind_info references should have been resolved");
+    return;
+  case invalid:
+    // Fall into llvm_unreachable().
+    break;
+  }
+  llvm_unreachable("unknown x86_64 Reference Kind");
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/Atoms.h b/lib/ReaderWriter/MachO/Atoms.h
new file mode 100644 (file)
index 0000000..573efca
--- /dev/null
@@ -0,0 +1,181 @@
+//===- lib/ReaderWriter/MachO/Atoms.h ---------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_ATOMS_H
+#define LLD_READER_WRITER_MACHO_ATOMS_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <string>
+
+namespace lld {
+
+class File;
+
+namespace mach_o {
+
+class MachODefinedAtom : public SimpleDefinedAtom {
+public:
+  MachODefinedAtom(const File &f, const StringRef name, Scope scope,
+                   ContentType type, Merge merge, bool thumb, bool noDeadStrip,
+                   const ArrayRef<uint8_t> content, Alignment align)
+      : SimpleDefinedAtom(f), _name(name), _content(content),
+        _align(align), _contentType(type), _scope(scope), _merge(merge),
+        _thumb(thumb), _noDeadStrip(noDeadStrip) {}
+
+  // Constructor for zero-fill content
+  MachODefinedAtom(const File &f, const StringRef name, Scope scope,
+                   ContentType type, uint64_t size, bool noDeadStrip,
+                   Alignment align)
+      : SimpleDefinedAtom(f), _name(name),
+        _content(ArrayRef<uint8_t>(nullptr, size)), _align(align),
+        _contentType(type), _scope(scope), _merge(mergeNo), _thumb(false),
+        _noDeadStrip(noDeadStrip) {}
+
+  ~MachODefinedAtom() override = default;
+
+  uint64_t size() const override { return _content.size(); }
+
+  ContentType contentType() const override { return _contentType; }
+
+  Alignment alignment() const override { return _align; }
+
+  StringRef name() const override { return _name; }
+
+  Scope scope() const override { return _scope; }
+
+  Merge merge() const override { return _merge; }
+
+  DeadStripKind deadStrip() const override {
+    if (_contentType == DefinedAtom::typeInitializerPtr)
+      return deadStripNever;
+    if (_contentType == DefinedAtom::typeTerminatorPtr)
+      return deadStripNever;
+    if (_noDeadStrip)
+      return deadStripNever;
+    return deadStripNormal;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    // Note: Zerofill atoms have a content pointer which is null.
+    return _content;
+  }
+
+  bool isThumb() const { return _thumb; }
+
+private:
+  const StringRef _name;
+  const ArrayRef<uint8_t> _content;
+  const DefinedAtom::Alignment _align;
+  const ContentType _contentType;
+  const Scope _scope;
+  const Merge _merge;
+  const bool _thumb;
+  const bool _noDeadStrip;
+};
+
+class MachODefinedCustomSectionAtom : public MachODefinedAtom {
+public:
+  MachODefinedCustomSectionAtom(const File &f, const StringRef name,
+                                Scope scope, ContentType type, Merge merge,
+                                bool thumb, bool noDeadStrip,
+                                const ArrayRef<uint8_t> content,
+                                StringRef sectionName, Alignment align)
+      : MachODefinedAtom(f, name, scope, type, merge, thumb, noDeadStrip,
+                         content, align),
+        _sectionName(sectionName) {}
+
+  ~MachODefinedCustomSectionAtom() override = default;
+
+  SectionChoice sectionChoice() const override {
+    return DefinedAtom::sectionCustomRequired;
+  }
+
+  StringRef customSectionName() const override {
+    return _sectionName;
+  }
+private:
+  StringRef _sectionName;
+};
+
+class MachOTentativeDefAtom : public SimpleDefinedAtom {
+public:
+  MachOTentativeDefAtom(const File &f, const StringRef name, Scope scope,
+                        uint64_t size, DefinedAtom::Alignment align)
+      : SimpleDefinedAtom(f), _name(name), _scope(scope), _size(size),
+        _align(align) {}
+
+  ~MachOTentativeDefAtom() override = default;
+
+  uint64_t size() const override { return _size; }
+
+  Merge merge() const override { return DefinedAtom::mergeAsTentative; }
+
+  ContentType contentType() const override { return DefinedAtom::typeZeroFill; }
+
+  Alignment alignment() const override { return _align; }
+
+  StringRef name() const override { return _name; }
+
+  Scope scope() const override { return _scope; }
+
+  ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+private:
+  const std::string _name;
+  const Scope _scope;
+  const uint64_t _size;
+  const DefinedAtom::Alignment _align;
+};
+
+class MachOSharedLibraryAtom : public SharedLibraryAtom {
+public:
+  MachOSharedLibraryAtom(const File &file, StringRef name,
+                         StringRef dylibInstallName, bool weakDef)
+      : SharedLibraryAtom(), _file(file), _name(name),
+        _dylibInstallName(dylibInstallName) {}
+  ~MachOSharedLibraryAtom() override = default;
+
+  StringRef loadName() const override { return _dylibInstallName; }
+
+  bool canBeNullAtRuntime() const override {
+    // FIXME: this may actually be changeable. For now, all symbols are strongly
+    // defined though.
+    return false;
+  }
+
+  const File &file() const override { return _file; }
+
+  StringRef name() const override { return _name; }
+
+  Type type() const override {
+    // Unused in MachO (I think).
+    return Type::Unknown;
+  }
+
+  uint64_t size() const override {
+    // Unused in MachO (I think)
+    return 0;
+  }
+
+private:
+  const File &_file;
+  StringRef _name;
+  StringRef _dylibInstallName;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5a96d87
--- /dev/null
@@ -0,0 +1,34 @@
+add_lld_library(lldMachO
+  ArchHandler.cpp
+  ArchHandler_arm.cpp
+  ArchHandler_arm64.cpp
+  ArchHandler_x86.cpp
+  ArchHandler_x86_64.cpp
+  CompactUnwindPass.cpp
+  GOTPass.cpp
+  LayoutPass.cpp
+  MachOLinkingContext.cpp
+  MachONormalizedFileBinaryReader.cpp
+  MachONormalizedFileBinaryWriter.cpp
+  MachONormalizedFileFromAtoms.cpp
+  MachONormalizedFileToAtoms.cpp
+  MachONormalizedFileYAML.cpp
+  ObjCPass.cpp
+  ShimPass.cpp
+  StubsPass.cpp
+  TLVPass.cpp
+  WriterMachO.cpp
+
+  LINK_COMPONENTS
+    DebugInfoDWARF
+    Object
+    Support
+    Demangle
+
+  LINK_LIBS
+    lldCore
+    lldYAML
+    ${LLVM_PTHREAD_LIB}
+  )
+
+include_directories(.)
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
new file mode 100644 (file)
index 0000000..49d5184
--- /dev/null
@@ -0,0 +1,582 @@
+//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file A pass to convert MachO's __compact_unwind sections into the final
+/// __unwind_info format used during runtime. See
+/// mach-o/compact_unwind_encoding.h for more details on the formats involved.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+
+#define DEBUG_TYPE "macho-compact-unwind"
+
+namespace lld {
+namespace mach_o {
+
+namespace {
+struct CompactUnwindEntry {
+  const Atom *rangeStart;
+  const Atom *personalityFunction;
+  const Atom *lsdaLocation;
+  const Atom *ehFrame;
+
+  uint32_t rangeLength;
+
+  // There are 3 types of compact unwind entry, distinguished by the encoding
+  // value: 0 indicates a function with no unwind info;
+  // _archHandler.dwarfCompactUnwindType() indicates that the entry defers to
+  // __eh_frame, and that the ehFrame entry will be valid; any other value is a
+  // real compact unwind entry -- personalityFunction will be set and
+  // lsdaLocation may be.
+  uint32_t encoding;
+
+  CompactUnwindEntry(const DefinedAtom *function)
+      : rangeStart(function), personalityFunction(nullptr),
+        lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(function->size()),
+        encoding(0) {}
+
+  CompactUnwindEntry()
+      : rangeStart(nullptr), personalityFunction(nullptr),
+        lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(0), encoding(0) {}
+};
+
+struct UnwindInfoPage {
+  ArrayRef<CompactUnwindEntry> entries;
+};
+}
+
+class UnwindInfoAtom : public SimpleDefinedAtom {
+public:
+  UnwindInfoAtom(ArchHandler &archHandler, const File &file, bool isBig,
+                 std::vector<const Atom *> &personalities,
+                 std::vector<uint32_t> &commonEncodings,
+                 std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs)
+      : SimpleDefinedAtom(file), _archHandler(archHandler),
+        _commonEncodingsOffset(7 * sizeof(uint32_t)),
+        _personalityArrayOffset(_commonEncodingsOffset +
+                                commonEncodings.size() * sizeof(uint32_t)),
+        _topLevelIndexOffset(_personalityArrayOffset +
+                             personalities.size() * sizeof(uint32_t)),
+        _lsdaIndexOffset(_topLevelIndexOffset +
+                         3 * (pages.size() + 1) * sizeof(uint32_t)),
+        _firstPageOffset(_lsdaIndexOffset + 2 * numLSDAs * sizeof(uint32_t)),
+        _isBig(isBig) {
+
+    addHeader(commonEncodings.size(), personalities.size(), pages.size());
+    addCommonEncodings(commonEncodings);
+    addPersonalityFunctions(personalities);
+    addTopLevelIndexes(pages);
+    addLSDAIndexes(pages, numLSDAs);
+    addSecondLevelPages(pages);
+  }
+
+  ~UnwindInfoAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeProcessedUnwindInfo;
+  }
+
+  Alignment alignment() const override { return 4; }
+
+  uint64_t size() const override { return _contents.size(); }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR__;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override { return _contents; }
+
+  void addHeader(uint32_t numCommon, uint32_t numPersonalities,
+                 uint32_t numPages) {
+    using normalized::write32;
+
+    uint32_t headerSize = 7 * sizeof(uint32_t);
+    _contents.resize(headerSize);
+
+    uint8_t *headerEntries = _contents.data();
+    // version
+    write32(headerEntries, 1, _isBig);
+    // commonEncodingsArraySectionOffset
+    write32(headerEntries + sizeof(uint32_t), _commonEncodingsOffset, _isBig);
+    // commonEncodingsArrayCount
+    write32(headerEntries + 2 * sizeof(uint32_t), numCommon, _isBig);
+    // personalityArraySectionOffset
+    write32(headerEntries + 3 * sizeof(uint32_t), _personalityArrayOffset,
+            _isBig);
+    // personalityArrayCount
+    write32(headerEntries + 4 * sizeof(uint32_t), numPersonalities, _isBig);
+    // indexSectionOffset
+    write32(headerEntries + 5 * sizeof(uint32_t), _topLevelIndexOffset, _isBig);
+    // indexCount
+    write32(headerEntries + 6 * sizeof(uint32_t), numPages + 1, _isBig);
+  }
+
+  /// Add the list of common encodings to the section; this is simply an array
+  /// of uint32_t compact values. Size has already been specified in the header.
+  void addCommonEncodings(std::vector<uint32_t> &commonEncodings) {
+    using normalized::write32;
+
+    _contents.resize(_commonEncodingsOffset +
+                     commonEncodings.size() * sizeof(uint32_t));
+    uint8_t *commonEncodingsArea =
+        reinterpret_cast<uint8_t *>(_contents.data() + _commonEncodingsOffset);
+
+    for (uint32_t encoding : commonEncodings) {
+      write32(commonEncodingsArea, encoding, _isBig);
+      commonEncodingsArea += sizeof(uint32_t);
+    }
+  }
+
+  void addPersonalityFunctions(std::vector<const Atom *> personalities) {
+    _contents.resize(_personalityArrayOffset +
+                     personalities.size() * sizeof(uint32_t));
+
+    for (unsigned i = 0; i < personalities.size(); ++i)
+      addImageReferenceIndirect(_personalityArrayOffset + i * sizeof(uint32_t),
+                                personalities[i]);
+  }
+
+  void addTopLevelIndexes(std::vector<UnwindInfoPage> &pages) {
+    using normalized::write32;
+
+    uint32_t numIndexes = pages.size() + 1;
+    _contents.resize(_topLevelIndexOffset + numIndexes * 3 * sizeof(uint32_t));
+
+    uint32_t pageLoc = _firstPageOffset;
+
+    // The most difficult job here is calculating the LSDAs; everything else
+    // follows fairly naturally, but we can't state where the first
+    uint8_t *indexData = &_contents[_topLevelIndexOffset];
+    uint32_t numLSDAs = 0;
+    for (unsigned i = 0; i < pages.size(); ++i) {
+      // functionOffset
+      addImageReference(_topLevelIndexOffset + 3 * i * sizeof(uint32_t),
+                        pages[i].entries[0].rangeStart);
+      // secondLevelPagesSectionOffset
+      write32(indexData + (3 * i + 1) * sizeof(uint32_t), pageLoc, _isBig);
+      write32(indexData + (3 * i + 2) * sizeof(uint32_t),
+              _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
+
+      for (auto &entry : pages[i].entries)
+        if (entry.lsdaLocation)
+          ++numLSDAs;
+    }
+
+    // Finally, write out the final sentinel index
+    auto &finalEntry = pages[pages.size() - 1].entries.back();
+    addImageReference(_topLevelIndexOffset +
+                          3 * pages.size() * sizeof(uint32_t),
+                      finalEntry.rangeStart, finalEntry.rangeLength);
+    // secondLevelPagesSectionOffset => 0
+    write32(indexData + (3 * pages.size() + 2) * sizeof(uint32_t),
+            _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
+  }
+
+  void addLSDAIndexes(std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) {
+    _contents.resize(_lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t));
+
+    uint32_t curOffset = _lsdaIndexOffset;
+    for (auto &page : pages) {
+      for (auto &entry : page.entries) {
+        if (!entry.lsdaLocation)
+          continue;
+
+        addImageReference(curOffset, entry.rangeStart);
+        addImageReference(curOffset + sizeof(uint32_t), entry.lsdaLocation);
+        curOffset += 2 * sizeof(uint32_t);
+      }
+    }
+  }
+
+  void addSecondLevelPages(std::vector<UnwindInfoPage> &pages) {
+    for (auto &page : pages) {
+      addRegularSecondLevelPage(page);
+    }
+  }
+
+  void addRegularSecondLevelPage(const UnwindInfoPage &page) {
+    uint32_t curPageOffset = _contents.size();
+    const int16_t headerSize = sizeof(uint32_t) + 2 * sizeof(uint16_t);
+    uint32_t curPageSize =
+        headerSize + 2 * page.entries.size() * sizeof(uint32_t);
+    _contents.resize(curPageOffset + curPageSize);
+
+    using normalized::write32;
+    using normalized::write16;
+    // 2 => regular page
+    write32(&_contents[curPageOffset], 2, _isBig);
+    // offset of 1st entry
+    write16(&_contents[curPageOffset + 4], headerSize, _isBig);
+    write16(&_contents[curPageOffset + 6], page.entries.size(), _isBig);
+
+    uint32_t pagePos = curPageOffset + headerSize;
+    for (auto &entry : page.entries) {
+      addImageReference(pagePos, entry.rangeStart);
+
+      write32(_contents.data() + pagePos + sizeof(uint32_t), entry.encoding,
+              _isBig);
+      if ((entry.encoding & 0x0f000000U) ==
+          _archHandler.dwarfCompactUnwindType())
+        addEhFrameReference(pagePos + sizeof(uint32_t), entry.ehFrame);
+
+      pagePos += 2 * sizeof(uint32_t);
+    }
+  }
+
+  void addEhFrameReference(uint32_t offset, const Atom *dest,
+                           Reference::Addend addend = 0) {
+    addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+                 _archHandler.unwindRefToEhFrameKind(), offset, dest, addend);
+  }
+
+  void addImageReference(uint32_t offset, const Atom *dest,
+                         Reference::Addend addend = 0) {
+    addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+                 _archHandler.imageOffsetKind(), offset, dest, addend);
+  }
+
+  void addImageReferenceIndirect(uint32_t offset, const Atom *dest) {
+    addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+                 _archHandler.imageOffsetKindIndirect(), offset, dest, 0);
+  }
+
+private:
+  mach_o::ArchHandler &_archHandler;
+  std::vector<uint8_t> _contents;
+  uint32_t _commonEncodingsOffset;
+  uint32_t _personalityArrayOffset;
+  uint32_t _topLevelIndexOffset;
+  uint32_t _lsdaIndexOffset;
+  uint32_t _firstPageOffset;
+  bool _isBig;
+};
+
+/// Pass for instantiating and optimizing GOT slots.
+///
+class CompactUnwindPass : public Pass {
+public:
+  CompactUnwindPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")),
+        _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+private:
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
+
+    std::map<const Atom *, CompactUnwindEntry> unwindLocs;
+    std::map<const Atom *, const Atom *> dwarfFrames;
+    std::vector<const Atom *> personalities;
+    uint32_t numLSDAs = 0;
+
+    // First collect all __compact_unwind and __eh_frame entries, addressable by
+    // the function referred to.
+    collectCompactUnwindEntries(mergedFile, unwindLocs, personalities,
+                                numLSDAs);
+
+    collectDwarfFrameEntries(mergedFile, dwarfFrames);
+
+    // Skip rest of pass if no unwind info.
+    if (unwindLocs.empty() && dwarfFrames.empty())
+      return llvm::Error::success();
+
+    // FIXME: if there are more than 4 personality functions then we need to
+    // defer to DWARF info for the ones we don't put in the list. They should
+    // also probably be sorted by frequency.
+    assert(personalities.size() <= 4);
+
+    // TODO: Find commmon encodings for use by compressed pages.
+    std::vector<uint32_t> commonEncodings;
+
+    // Now sort the entries by final address and fixup the compact encoding to
+    // its final form (i.e. set personality function bits & create DWARF
+    // references where needed).
+    std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries(
+        mergedFile, unwindLocs, personalities, dwarfFrames);
+
+    // Remove any unused eh-frame atoms.
+    pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames);
+
+    // Finally, we can start creating pages based on these entries.
+
+    DEBUG(llvm::dbgs() << "  Splitting entries into pages\n");
+    // FIXME: we split the entries into pages naively: lots of 4k pages followed
+    // by a small one. ld64 tried to minimize space and align them to real 4k
+    // boundaries. That might be worth doing, or perhaps we could perform some
+    // minor balancing for expected number of lookups.
+    std::vector<UnwindInfoPage> pages;
+    auto remainingInfos = llvm::makeArrayRef(unwindInfos);
+    do {
+      pages.push_back(UnwindInfoPage());
+
+      // FIXME: we only create regular pages at the moment. These can hold up to
+      // 1021 entries according to the documentation.
+      unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size());
+
+      pages.back().entries = remainingInfos.slice(0, entriesInPage);
+      remainingInfos = remainingInfos.slice(entriesInPage);
+
+      DEBUG(llvm::dbgs()
+            << "    Page from " << pages.back().entries[0].rangeStart->name()
+            << " to " << pages.back().entries.back().rangeStart->name() << " + "
+            << llvm::format("0x%x", pages.back().entries.back().rangeLength)
+            << " has " << entriesInPage << " entries\n");
+    } while (!remainingInfos.empty());
+
+    auto *unwind = new (_file.allocator())
+        UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
+                       commonEncodings, pages, numLSDAs);
+    mergedFile.addAtom(*unwind);
+
+    // Finally, remove all __compact_unwind atoms now that we've processed them.
+    mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) {
+      return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
+    });
+
+    return llvm::Error::success();
+  }
+
+  void collectCompactUnwindEntries(
+      const SimpleFile &mergedFile,
+      std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+      std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
+    DEBUG(llvm::dbgs() << "  Collecting __compact_unwind entries\n");
+
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
+        continue;
+
+      auto unwindEntry = extractCompactUnwindEntry(atom);
+      unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry));
+
+      DEBUG(llvm::dbgs() << "    Entry for " << unwindEntry.rangeStart->name()
+                         << ", encoding="
+                         << llvm::format("0x%08x", unwindEntry.encoding));
+      if (unwindEntry.personalityFunction)
+        DEBUG(llvm::dbgs() << ", personality="
+                           << unwindEntry.personalityFunction->name()
+                           << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
+      DEBUG(llvm::dbgs() << '\n');
+
+      // Count number of LSDAs we see, since we need to know how big the index
+      // will be while laying out the section.
+      if (unwindEntry.lsdaLocation)
+        ++numLSDAs;
+
+      // Gather the personality functions now, so that they're in deterministic
+      // order (derived from the DefinedAtom order).
+      if (unwindEntry.personalityFunction) {
+        auto pFunc = std::find(personalities.begin(), personalities.end(),
+                               unwindEntry.personalityFunction);
+        if (pFunc == personalities.end())
+          personalities.push_back(unwindEntry.personalityFunction);
+      }
+    }
+  }
+
+  CompactUnwindEntry extractCompactUnwindEntry(const DefinedAtom *atom) {
+    CompactUnwindEntry entry;
+
+    for (const Reference *ref : *atom) {
+      switch (ref->offsetInAtom()) {
+      case 0:
+        // FIXME: there could legitimately be functions with multiple encoding
+        // entries. However, nothing produces them at the moment.
+        assert(ref->addend() == 0 && "unexpected offset into function");
+        entry.rangeStart = ref->target();
+        break;
+      case 0x10:
+        assert(ref->addend() == 0 && "unexpected offset into personality fn");
+        entry.personalityFunction = ref->target();
+        break;
+      case 0x18:
+        assert(ref->addend() == 0 && "unexpected offset into LSDA atom");
+        entry.lsdaLocation = ref->target();
+        break;
+      }
+    }
+
+    if (atom->rawContent().size() < 4 * sizeof(uint32_t))
+      return entry;
+
+    using normalized::read32;
+    entry.rangeLength =
+        read32(atom->rawContent().data() + 2 * sizeof(uint32_t), _isBig);
+    entry.encoding =
+        read32(atom->rawContent().data() + 3 * sizeof(uint32_t), _isBig);
+    return entry;
+  }
+
+  void
+  collectDwarfFrameEntries(const SimpleFile &mergedFile,
+                           std::map<const Atom *, const Atom *> &dwarfFrames) {
+    for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) {
+      if (ehFrameAtom->contentType() != DefinedAtom::typeCFI)
+        continue;
+      if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom))
+        continue;
+
+      if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom))
+        dwarfFrames[function] = ehFrameAtom;
+    }
+  }
+
+  /// Every atom defined in __TEXT,__text needs an entry in the final
+  /// __unwind_info section (in order). These comes from two sources:
+  ///   + Input __compact_unwind sections where possible (after adding the
+  ///      personality function offset which is only known now).
+  ///   + A synthesised reference to __eh_frame if there's no __compact_unwind
+  ///     or too many personality functions to be accommodated.
+  std::vector<CompactUnwindEntry> createUnwindInfoEntries(
+      const SimpleFile &mergedFile,
+      const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+      const std::vector<const Atom *> &personalities,
+      const std::map<const Atom *, const Atom *> &dwarfFrames) {
+    std::vector<CompactUnwindEntry> unwindInfos;
+
+    DEBUG(llvm::dbgs() << "  Creating __unwind_info entries\n");
+    // The final order in the __unwind_info section must be derived from the
+    // order of typeCode atoms, since that's how they'll be put into the object
+    // file eventually (yuck!).
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      if (atom->contentType() != DefinedAtom::typeCode)
+        continue;
+
+      unwindInfos.push_back(finalizeUnwindInfoEntryForAtom(
+          atom, unwindLocs, personalities, dwarfFrames));
+
+      DEBUG(llvm::dbgs() << "    Entry for " << atom->name()
+                         << ", final encoding="
+                         << llvm::format("0x%08x", unwindInfos.back().encoding)
+                         << '\n');
+    }
+
+    return unwindInfos;
+  }
+
+  /// Remove unused EH frames.
+  ///
+  /// An EH frame is considered unused if there is a corresponding compact
+  /// unwind atom that doesn't require the EH frame.
+  void pruneUnusedEHFrames(
+                   SimpleFile &mergedFile,
+                   const std::vector<CompactUnwindEntry> &unwindInfos,
+                   const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+                   const std::map<const Atom *, const Atom *> &dwarfFrames) {
+
+    // Worklist of all 'used' FDEs.
+    std::vector<const DefinedAtom *> usedDwarfWorklist;
+
+    // We have to check two conditions when building the worklist:
+    // (1) EH frames used by compact unwind entries.
+    for (auto &entry : unwindInfos)
+      if (entry.ehFrame)
+        usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame));
+
+    // (2) EH frames that reference functions with no corresponding compact
+    //     unwind info.
+    for (auto &entry : dwarfFrames)
+      if (!unwindLocs.count(entry.first))
+        usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second));
+
+    // Add all transitively referenced CFI atoms by processing the worklist.
+    std::set<const Atom *> usedDwarfFrames;
+    while (!usedDwarfWorklist.empty()) {
+      const DefinedAtom *cfiAtom = usedDwarfWorklist.back();
+      usedDwarfWorklist.pop_back();
+      usedDwarfFrames.insert(cfiAtom);
+      for (const auto *ref : *cfiAtom) {
+        const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target());
+        if (cfiTarget->contentType() == DefinedAtom::typeCFI)
+          usedDwarfWorklist.push_back(cfiTarget);
+      }
+    }
+
+    // Finally, delete all unreferenced CFI atoms.
+    mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) {
+      if ((atom->contentType() == DefinedAtom::typeCFI) &&
+          !usedDwarfFrames.count(atom))
+        return true;
+      return false;
+    });
+  }
+
+  CompactUnwindEntry finalizeUnwindInfoEntryForAtom(
+      const DefinedAtom *function,
+      const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+      const std::vector<const Atom *> &personalities,
+      const std::map<const Atom *, const Atom *> &dwarfFrames) {
+    auto unwindLoc = unwindLocs.find(function);
+
+    CompactUnwindEntry entry;
+    if (unwindLoc == unwindLocs.end()) {
+      // Default entry has correct encoding (0 => no unwind), but we need to
+      // synthesise the function.
+      entry.rangeStart = function;
+      entry.rangeLength = function->size();
+    } else
+      entry = unwindLoc->second;
+
+
+    // If there's no __compact_unwind entry, or it explicitly says to use
+    // __eh_frame, we need to try and fill in the correct DWARF atom.
+    if (entry.encoding == _archHandler.dwarfCompactUnwindType() ||
+        entry.encoding == 0) {
+      auto dwarfFrame = dwarfFrames.find(function);
+      if (dwarfFrame != dwarfFrames.end()) {
+        entry.encoding = _archHandler.dwarfCompactUnwindType();
+        entry.ehFrame = dwarfFrame->second;
+      }
+    }
+
+    auto personality = std::find(personalities.begin(), personalities.end(),
+                                 entry.personalityFunction);
+    uint32_t personalityIdx = personality == personalities.end()
+                                  ? 0
+                                  : personality - personalities.begin() + 1;
+
+    // FIXME: We should also use DWARF when there isn't enough room for the
+    // personality function in the compact encoding.
+    assert(personalityIdx < 4 && "too many personality functions");
+
+    entry.encoding |= personalityIdx << 28;
+
+    if (entry.lsdaLocation)
+      entry.encoding |= 1U << 30;
+
+    return entry;
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler &_archHandler;
+  MachOFile &_file;
+  bool _isBig;
+};
+
+void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  assert(ctx.needsCompactUnwindPass());
+  pm.add(llvm::make_unique<CompactUnwindPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/DebugInfo.h b/lib/ReaderWriter/MachO/DebugInfo.h
new file mode 100644 (file)
index 0000000..28e41bf
--- /dev/null
@@ -0,0 +1,106 @@
+//===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_DEBUGINFO_H
+#define LLD_READER_WRITER_MACHO_DEBUGINFO_H
+
+#include "lld/Core/Atom.h"
+#include <vector>
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+
+namespace lld {
+namespace mach_o {
+
+class DebugInfo {
+public:
+  enum class Kind {
+    Dwarf,
+    Stabs
+  };
+
+  Kind kind() const { return _kind; }
+
+  void setAllocator(std::unique_ptr<llvm::BumpPtrAllocator> allocator) {
+    _allocator = std::move(allocator);
+  }
+
+protected:
+  DebugInfo(Kind kind) : _kind(kind) {}
+
+private:
+  std::unique_ptr<llvm::BumpPtrAllocator> _allocator;
+  Kind _kind;
+};
+
+struct TranslationUnitSource {
+  StringRef name;
+  StringRef path;
+};
+
+class DwarfDebugInfo : public DebugInfo {
+public:
+  DwarfDebugInfo(TranslationUnitSource tu)
+    : DebugInfo(Kind::Dwarf), _tu(std::move(tu)) {}
+
+  static inline bool classof(const DebugInfo *di) {
+    return di->kind() == Kind::Dwarf;
+  }
+
+  const TranslationUnitSource &translationUnitSource() const { return _tu; }
+
+private:
+  TranslationUnitSource _tu;
+};
+
+struct Stab {
+  Stab(const Atom* atom, uint8_t type, uint8_t other, uint16_t desc,
+       uint32_t value, StringRef str)
+    : atom(atom), type(type), other(other), desc(desc), value(value),
+      str(str) {}
+
+  const class Atom*   atom;
+  uint8_t             type;
+  uint8_t             other;
+  uint16_t            desc;
+  uint32_t            value;
+  StringRef           str;
+};
+
+inline raw_ostream& operator<<(raw_ostream &os, Stab &s) {
+  os << "Stab -- atom: " << llvm::format("%p", s.atom) << ", type: " << (uint32_t)s.type
+     << ", other: " << (uint32_t)s.other << ", desc: " << s.desc << ", value: " << s.value
+     << ", str: '" << s.str << "'";
+  return os;
+}
+
+class StabsDebugInfo : public DebugInfo {
+public:
+
+  typedef std::vector<Stab> StabsList;
+
+  StabsDebugInfo(StabsList stabs)
+    : DebugInfo(Kind::Stabs), _stabs(std::move(stabs)) {}
+
+  static inline bool classof(const DebugInfo *di) {
+    return di->kind() == Kind::Stabs;
+  }
+
+  const StabsList& stabs() const { return _stabs; }
+
+public:
+  StabsList _stabs;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_DEBUGINFO_H
diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lib/ReaderWriter/MachO/ExecutableAtoms.h
new file mode 100644 (file)
index 0000000..ab14e6d
--- /dev/null
@@ -0,0 +1,155 @@
+//===- lib/ReaderWriter/MachO/ExecutableAtoms.h ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
+#define LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
+
+#include "Atoms.h"
+#include "File.h"
+
+#include "llvm/BinaryFormat/MachO.h"
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+
+//
+// CEntryFile adds an UndefinedAtom for "_main" so that the Resolving
+// phase will fail if "_main" is undefined.
+//
+class CEntryFile : public SimpleFile {
+public:
+  CEntryFile(const MachOLinkingContext &context)
+      : SimpleFile("C entry", kindCEntryObject),
+       _undefMain(*this, context.entrySymbolName()) {
+    this->addAtom(_undefMain);
+  }
+
+private:
+  SimpleUndefinedAtom   _undefMain;
+};
+
+
+//
+// StubHelperFile adds an UndefinedAtom for "dyld_stub_binder" so that
+// the Resolveing phase will fail if "dyld_stub_binder" is undefined.
+//
+class StubHelperFile : public SimpleFile {
+public:
+  StubHelperFile(const MachOLinkingContext &context)
+      : SimpleFile("stub runtime", kindStubHelperObject),
+        _undefBinder(*this, context.binderSymbolName()) {
+    this->addAtom(_undefBinder);
+  }
+
+private:
+  SimpleUndefinedAtom   _undefBinder;
+};
+
+
+//
+// MachHeaderAliasFile lazily instantiates the magic symbols that mark the start
+// of the mach_header for final linked images.
+//
+class MachHeaderAliasFile : public SimpleFile {
+public:
+  MachHeaderAliasFile(const MachOLinkingContext &context)
+    : SimpleFile("mach_header symbols", kindHeaderObject) {
+    StringRef machHeaderSymbolName;
+    DefinedAtom::Scope symbolScope = DefinedAtom::scopeLinkageUnit;
+    StringRef dsoHandleName;
+    switch (context.outputMachOType()) {
+    case llvm::MachO::MH_OBJECT:
+      machHeaderSymbolName = "__mh_object_header";
+      break;
+    case llvm::MachO::MH_EXECUTE:
+      machHeaderSymbolName = "__mh_execute_header";
+      symbolScope = DefinedAtom::scopeGlobal;
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_FVMLIB:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_CORE:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_PRELOAD:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_DYLIB:
+      machHeaderSymbolName = "__mh_dylib_header";
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_DYLINKER:
+      machHeaderSymbolName = "__mh_dylinker_header";
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_BUNDLE:
+      machHeaderSymbolName = "__mh_bundle_header";
+      dsoHandleName = "___dso_handle";
+      break;
+    case llvm::MachO::MH_DYLIB_STUB:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_DSYM:
+      llvm_unreachable("no mach_header symbol for file type");
+    case llvm::MachO::MH_KEXT_BUNDLE:
+      dsoHandleName = "___dso_handle";
+      break;
+    }
+    if (!machHeaderSymbolName.empty())
+      _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+          *this, machHeaderSymbolName, symbolScope,
+          DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false,
+          true /* noDeadStrip */,
+          ArrayRef<uint8_t>(), DefinedAtom::Alignment(4096)));
+
+    if (!dsoHandleName.empty())
+      _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+          *this, dsoHandleName, DefinedAtom::scopeLinkageUnit,
+          DefinedAtom::typeDSOHandle, DefinedAtom::mergeNo, false,
+          true /* noDeadStrip */,
+          ArrayRef<uint8_t>(), DefinedAtom::Alignment(1)));
+  }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _definedAtoms;
+  }
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _definedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+
+
+private:
+  mutable AtomVector<DefinedAtom> _definedAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h
new file mode 100644 (file)
index 0000000..2bdd634
--- /dev/null
@@ -0,0 +1,400 @@
+//===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_FILE_H
+#define LLD_READER_WRITER_MACHO_FILE_H
+
+#include "Atoms.h"
+#include "DebugInfo.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Format.h"
+#include <unordered_map>
+
+namespace lld {
+namespace mach_o {
+
+using lld::mach_o::normalized::Section;
+
+class MachOFile : public SimpleFile {
+public:
+
+  /// Real file constructor - for on-disk files.
+  MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+    : SimpleFile(mb->getBufferIdentifier(), File::kindMachObject),
+      _mb(std::move(mb)), _ctx(ctx) {}
+
+  /// Dummy file constructor - for virtual files.
+  MachOFile(StringRef path)
+    : SimpleFile(path, File::kindMachObject) {}
+
+  void addDefinedAtom(StringRef name, Atom::Scope scope,
+                      DefinedAtom::ContentType type, DefinedAtom::Merge merge,
+                      uint64_t sectionOffset, uint64_t contentSize, bool thumb,
+                      bool noDeadStrip, bool copyRefs,
+                      const Section *inSection) {
+    assert(sectionOffset+contentSize <= inSection->content.size());
+    ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+                                                        contentSize);
+    if (copyRefs) {
+      // Make a copy of the atom's name and content that is owned by this file.
+      name = name.copy(allocator());
+      content = content.copy(allocator());
+    }
+    DefinedAtom::Alignment align(
+        inSection->alignment,
+        sectionOffset % inSection->alignment);
+    auto *atom =
+        new (allocator()) MachODefinedAtom(*this, name, scope, type, merge,
+                                           thumb, noDeadStrip, content, align);
+    addAtomForSection(inSection, atom, sectionOffset);
+  }
+
+  void addDefinedAtomInCustomSection(StringRef name, Atom::Scope scope,
+                      DefinedAtom::ContentType type, DefinedAtom::Merge merge,
+                      bool thumb, bool noDeadStrip, uint64_t sectionOffset,
+                      uint64_t contentSize, StringRef sectionName,
+                      bool copyRefs, const Section *inSection) {
+    assert(sectionOffset+contentSize <= inSection->content.size());
+    ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+                                                        contentSize);
+   if (copyRefs) {
+      // Make a copy of the atom's name and content that is owned by this file.
+      name = name.copy(allocator());
+      content = content.copy(allocator());
+      sectionName = sectionName.copy(allocator());
+    }
+    DefinedAtom::Alignment align(
+        inSection->alignment,
+        sectionOffset % inSection->alignment);
+    auto *atom =
+        new (allocator()) MachODefinedCustomSectionAtom(*this, name, scope, type,
+                                                        merge, thumb,
+                                                        noDeadStrip, content,
+                                                        sectionName, align);
+    addAtomForSection(inSection, atom, sectionOffset);
+  }
+
+  void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope,
+                              uint64_t sectionOffset, uint64_t size,
+                              bool noDeadStrip, bool copyRefs,
+                              const Section *inSection) {
+    if (copyRefs) {
+      // Make a copy of the atom's name and content that is owned by this file.
+      name = name.copy(allocator());
+    }
+    DefinedAtom::Alignment align(
+        inSection->alignment,
+        sectionOffset % inSection->alignment);
+
+    DefinedAtom::ContentType type = DefinedAtom::typeUnknown;
+    switch (inSection->type) {
+    case llvm::MachO::S_ZEROFILL:
+      type = DefinedAtom::typeZeroFill;
+      break;
+    case llvm::MachO::S_THREAD_LOCAL_ZEROFILL:
+      type = DefinedAtom::typeTLVInitialZeroFill;
+      break;
+    default:
+      llvm_unreachable("Unrecognized zero-fill section");
+    }
+
+    auto *atom =
+        new (allocator()) MachODefinedAtom(*this, name, scope, type, size,
+                                           noDeadStrip, align);
+    addAtomForSection(inSection, atom, sectionOffset);
+  }
+
+  void addUndefinedAtom(StringRef name, bool copyRefs) {
+    if (copyRefs) {
+      // Make a copy of the atom's name that is owned by this file.
+      name = name.copy(allocator());
+    }
+    auto *atom = new (allocator()) SimpleUndefinedAtom(*this, name);
+    addAtom(*atom);
+    _undefAtoms[name] = atom;
+  }
+
+  void addTentativeDefAtom(StringRef name, Atom::Scope scope, uint64_t size,
+                           DefinedAtom::Alignment align, bool copyRefs) {
+    if (copyRefs) {
+      // Make a copy of the atom's name that is owned by this file.
+      name = name.copy(allocator());
+    }
+    auto *atom =
+        new (allocator()) MachOTentativeDefAtom(*this, name, scope, size, align);
+    addAtom(*atom);
+    _undefAtoms[name] = atom;
+  }
+
+  /// Search this file for an the atom from 'section' that covers
+  /// 'offsetInSect'.  Returns nullptr is no atom found.
+  MachODefinedAtom *findAtomCoveringAddress(const Section &section,
+                                            uint64_t offsetInSect,
+                                            uint32_t *foundOffsetAtom=nullptr) {
+    const auto &pos = _sectionAtoms.find(&section);
+    if (pos == _sectionAtoms.end())
+      return nullptr;
+    const auto &vec = pos->second;
+    assert(offsetInSect < section.content.size());
+    // Vector of atoms for section are already sorted, so do binary search.
+    const auto &atomPos = std::lower_bound(vec.begin(), vec.end(), offsetInSect,
+        [offsetInSect](const SectionOffsetAndAtom &ao,
+                       uint64_t targetAddr) -> bool {
+          // Each atom has a start offset of its slice of the
+          // section's content. This compare function must return true
+          // iff the atom's range is before the offset being searched for.
+          uint64_t atomsEndOffset = ao.offset+ao.atom->rawContent().size();
+          return (atomsEndOffset <= offsetInSect);
+        });
+    if (atomPos == vec.end())
+      return nullptr;
+    if (foundOffsetAtom)
+      *foundOffsetAtom = offsetInSect - atomPos->offset;
+    return atomPos->atom;
+  }
+
+  /// Searches this file for an UndefinedAtom named 'name'. Returns
+  /// nullptr is no such atom found.
+  const lld::Atom *findUndefAtom(StringRef name) {
+    auto pos = _undefAtoms.find(name);
+    if (pos == _undefAtoms.end())
+      return nullptr;
+    return pos->second;
+  }
+
+  typedef std::function<void (MachODefinedAtom* atom)> DefinedAtomVisitor;
+
+  void eachDefinedAtom(DefinedAtomVisitor vistor) {
+    for (auto &sectAndAtoms : _sectionAtoms) {
+      for (auto &offAndAtom : sectAndAtoms.second) {
+        vistor(offAndAtom.atom);
+      }
+    }
+  }
+
+  typedef std::function<void(MachODefinedAtom *atom, uint64_t offset)>
+      SectionAtomVisitor;
+
+  void eachAtomInSection(const Section &section, SectionAtomVisitor visitor) {
+    auto pos = _sectionAtoms.find(&section);
+    if (pos == _sectionAtoms.end())
+      return;
+    auto vec = pos->second;
+
+    for (auto &offAndAtom : vec)
+      visitor(offAndAtom.atom, offAndAtom.offset);
+  }
+
+  MachOLinkingContext::Arch arch() const { return _arch; }
+  void setArch(MachOLinkingContext::Arch arch) { _arch = arch; }
+
+  MachOLinkingContext::OS OS() const { return _os; }
+  void setOS(MachOLinkingContext::OS os) { _os = os; }
+
+  MachOLinkingContext::ObjCConstraint objcConstraint() const {
+    return _objcConstraint;
+  }
+  void setObjcConstraint(MachOLinkingContext::ObjCConstraint v) {
+    _objcConstraint = v;
+  }
+
+  uint32_t minVersion() const { return _minVersion; }
+  void setMinVersion(uint32_t v) { _minVersion = v; }
+
+  LoadCommandType minVersionLoadCommandKind() const {
+    return _minVersionLoadCommandKind;
+  }
+  void setMinVersionLoadCommandKind(LoadCommandType v) {
+    _minVersionLoadCommandKind = v;
+  }
+
+  uint32_t swiftVersion() const { return _swiftVersion; }
+  void setSwiftVersion(uint32_t v) { _swiftVersion = v; }
+
+  bool subsectionsViaSymbols() const {
+    return _flags & llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+  }
+  void setFlags(normalized::FileFlags v) { _flags = v; }
+
+  /// Methods for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const File *F) {
+    return F->kind() == File::kindMachObject;
+  }
+
+  void setDebugInfo(std::unique_ptr<DebugInfo> debugInfo) {
+    _debugInfo = std::move(debugInfo);
+  }
+
+  DebugInfo* debugInfo() const { return _debugInfo.get(); }
+  std::unique_ptr<DebugInfo> takeDebugInfo() { return std::move(_debugInfo); }
+
+protected:
+  std::error_code doParse() override {
+    // Convert binary file to normalized mach-o.
+    auto normFile = normalized::readBinary(_mb, _ctx->arch());
+    if (auto ec = normFile.takeError())
+      return llvm::errorToErrorCode(std::move(ec));
+    // Convert normalized mach-o to atoms.
+    if (auto ec = normalized::normalizedObjectToAtoms(this, **normFile, false))
+      return llvm::errorToErrorCode(std::move(ec));
+    return std::error_code();
+  }
+
+private:
+  struct SectionOffsetAndAtom { uint64_t offset;  MachODefinedAtom *atom; };
+
+  void addAtomForSection(const Section *inSection, MachODefinedAtom* atom,
+                         uint64_t sectionOffset) {
+    SectionOffsetAndAtom offAndAtom;
+    offAndAtom.offset = sectionOffset;
+    offAndAtom.atom   = atom;
+     _sectionAtoms[inSection].push_back(offAndAtom);
+    addAtom(*atom);
+  }
+
+  typedef llvm::DenseMap<const normalized::Section *,
+                         std::vector<SectionOffsetAndAtom>>  SectionToAtoms;
+  typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+  std::unique_ptr<MemoryBuffer> _mb;
+  MachOLinkingContext          *_ctx;
+  SectionToAtoms                _sectionAtoms;
+  NameToAtom                     _undefAtoms;
+  MachOLinkingContext::Arch      _arch = MachOLinkingContext::arch_unknown;
+  MachOLinkingContext::OS        _os = MachOLinkingContext::OS::unknown;
+  uint32_t                       _minVersion = 0;
+  LoadCommandType               _minVersionLoadCommandKind = (LoadCommandType)0;
+  MachOLinkingContext::ObjCConstraint _objcConstraint =
+      MachOLinkingContext::objc_unknown;
+  uint32_t                       _swiftVersion = 0;
+  normalized::FileFlags        _flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+  std::unique_ptr<DebugInfo>   _debugInfo;
+};
+
+class MachODylibFile : public SharedLibraryFile {
+public:
+  MachODylibFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+      : SharedLibraryFile(mb->getBufferIdentifier()),
+        _mb(std::move(mb)), _ctx(ctx) {}
+
+  MachODylibFile(StringRef path) : SharedLibraryFile(path) {}
+
+  OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+    // Pass down _installName so that if this requested symbol
+    // is re-exported through this dylib, the SharedLibraryAtom's loadName()
+    // is this dylib installName and not the implementation dylib's.
+    // NOTE: isData is not needed for dylibs (it matters for static libs).
+    return exports(name, _installName);
+  }
+
+  /// Adds symbol name that this dylib exports. The corresponding
+  /// SharedLibraryAtom is created lazily (since most symbols are not used).
+  void addExportedSymbol(StringRef name, bool weakDef, bool copyRefs) {
+    if (copyRefs) {
+      name = name.copy(allocator());
+    }
+    AtomAndFlags info(weakDef);
+    _nameToAtom[name] = info;
+  }
+
+  void addReExportedDylib(StringRef dylibPath) {
+    _reExportedDylibs.emplace_back(dylibPath);
+  }
+
+  StringRef installName() const { return _installName; }
+  uint32_t currentVersion() { return _currentVersion; }
+  uint32_t compatVersion() { return _compatVersion; }
+
+  void setInstallName(StringRef name) { _installName = name; }
+  void setCompatVersion(uint32_t version) { _compatVersion = version; }
+  void setCurrentVersion(uint32_t version) { _currentVersion = version; }
+
+  typedef std::function<MachODylibFile *(StringRef)> FindDylib;
+
+  void loadReExportedDylibs(FindDylib find) {
+    for (ReExportedDylib &entry : _reExportedDylibs) {
+      entry.file = find(entry.path);
+    }
+  }
+
+  StringRef getDSOName() const override { return _installName; }
+
+  std::error_code doParse() override {
+    // Convert binary file to normalized mach-o.
+    auto normFile = normalized::readBinary(_mb, _ctx->arch());
+    if (auto ec = normFile.takeError())
+      return llvm::errorToErrorCode(std::move(ec));
+    // Convert normalized mach-o to atoms.
+    if (auto ec = normalized::normalizedDylibToAtoms(this, **normFile, false))
+      return llvm::errorToErrorCode(std::move(ec));
+    return std::error_code();
+  }
+
+private:
+  OwningAtomPtr<SharedLibraryAtom> exports(StringRef name,
+                                   StringRef installName) const {
+    // First, check if requested symbol is directly implemented by this dylib.
+    auto entry = _nameToAtom.find(name);
+    if (entry != _nameToAtom.end()) {
+      // FIXME: Make this map a set and only used in assert builds.
+      // Note, its safe to assert here as the resolver is the only client of
+      // this API and it only requests exports for undefined symbols.
+      // If we return from here we are no longer undefined so we should never
+      // get here again.
+      assert(!entry->second.atom && "Duplicate shared library export");
+      bool weakDef = entry->second.weakDef;
+      auto *atom = new (allocator()) MachOSharedLibraryAtom(*this, name,
+                                                            installName,
+                                                            weakDef);
+      entry->second.atom = atom;
+      return atom;
+    }
+
+    // Next, check if symbol is implemented in some re-exported dylib.
+    for (const ReExportedDylib &dylib : _reExportedDylibs) {
+      assert(dylib.file);
+      auto atom = dylib.file->exports(name, installName);
+      if (atom.get())
+        return atom;
+    }
+
+    // Symbol not exported or re-exported by this dylib.
+    return nullptr;
+  }
+
+  struct ReExportedDylib {
+    ReExportedDylib(StringRef p) : path(p), file(nullptr) { }
+    StringRef       path;
+    MachODylibFile *file;
+  };
+
+  struct AtomAndFlags {
+    AtomAndFlags() : atom(nullptr), weakDef(false) { }
+    AtomAndFlags(bool weak) : atom(nullptr), weakDef(weak) { }
+    const SharedLibraryAtom  *atom;
+    bool                      weakDef;
+  };
+
+  std::unique_ptr<MemoryBuffer>              _mb;
+  MachOLinkingContext                       *_ctx;
+  StringRef                                  _installName;
+  uint32_t                                   _currentVersion;
+  uint32_t                                   _compatVersion;
+  std::vector<ReExportedDylib>               _reExportedDylibs;
+  mutable std::unordered_map<StringRef, AtomAndFlags> _nameToAtom;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_FILE_H
diff --git a/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
new file mode 100644 (file)
index 0000000..76d2958
--- /dev/null
@@ -0,0 +1,61 @@
+//===- lib/ReaderWriter/MachO/FlatNamespaceFile.h -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
+#define LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
+
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class FlatNamespaceFile : public SharedLibraryFile {
+public:
+  FlatNamespaceFile(const MachOLinkingContext &context)
+    : SharedLibraryFile("flat namespace") { }
+
+  OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+    return new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(),
+                                                    false);
+  }
+
+  StringRef getDSOName() const override { return "flat-namespace"; }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _noDefinedAtoms;
+  }
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _noDefinedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp
new file mode 100644 (file)
index 0000000..8458a1c
--- /dev/null
@@ -0,0 +1,184 @@
+//===- lib/ReaderWriter/MachO/GOTPass.cpp -----------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This linker pass transforms all GOT kind references to real references.
+/// That is, in assembly you can write something like:
+///     movq foo@GOTPCREL(%rip), %rax
+/// which means you want to load a pointer to "foo" out of the GOT (global
+/// Offsets Table). In the object file, the Atom containing this instruction
+/// has a Reference whose target is an Atom named "foo" and the Reference
+/// kind is a GOT load.  The linker needs to instantiate a pointer sized
+/// GOT entry.  This is done be creating a GOT Atom to represent that pointer
+/// sized data in this pass, and altering the Atom graph so the Reference now
+/// points to the GOT Atom entry (corresponding to "foo") and changing the
+/// Reference Kind to reflect it is now pointing to a GOT entry (rather
+/// then needing a GOT entry).
+///
+/// There is one optimization the linker can do here.  If the target of the GOT
+/// is in the same linkage unit and does not need to be interposable, and
+/// the GOT use is just a load (not some other operation), this pass can
+/// transform that load into an LEA (add).  This optimizes away one memory load
+/// which at runtime that could stall the pipeline.  This optimization only
+/// works for architectures in which a (GOT) load instruction can be change to
+/// an LEA instruction that is the same size.  The method isGOTAccess() should
+/// only return true for "canBypassGOT" if this optimization is supported.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+//  GOT Entry Atom created by the GOT pass.
+//
+class GOTEntryAtom : public SimpleDefinedAtom {
+public:
+  GOTEntryAtom(const File &file, bool is64, StringRef name)
+    : SimpleDefinedAtom(file), _is64(is64), _name(name) { }
+
+  ~GOTEntryAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeGOT;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+  StringRef slotName() const {
+    return _name;
+  }
+
+private:
+  const bool _is64;
+  StringRef _name;
+};
+
+/// Pass for instantiating and optimizing GOT slots.
+///
+class GOTPass : public Pass {
+public:
+  GOTPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o GOT Pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+private:
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at instructions accessing the GOT.
+        bool canBypassGOT;
+        if (!_archHandler.isGOTAccess(*ref, canBypassGOT))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+
+        if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
+          // Update reference kind to reflect that target is a direct accesss.
+          _archHandler.updateReferenceToGOT(ref, false);
+        } else {
+          // Replace the target with a reference to a GOT entry.
+          const DefinedAtom *gotEntry = makeGOTEntry(target);
+          const_cast<Reference *>(ref)->setTarget(gotEntry);
+          // Update reference kind to reflect that target is now a GOT entry.
+          _archHandler.updateReferenceToGOT(ref, true);
+        }
+      }
+    }
+
+    // Sort and add all created GOT Atoms to master file
+    std::vector<const GOTEntryAtom *> entries;
+    entries.reserve(_targetToGOT.size());
+    for (auto &it : _targetToGOT)
+      entries.push_back(it.second);
+    std::sort(entries.begin(), entries.end(),
+              [](const GOTEntryAtom *left, const GOTEntryAtom *right) {
+      return (left->slotName().compare(right->slotName()) < 0);
+    });
+    for (const GOTEntryAtom *slot : entries)
+      mergedFile.addAtom(*slot);
+
+    return llvm::Error::success();
+  }
+
+  bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
+    // Accesses to shared library symbols must go through GOT.
+    if (isa<SharedLibraryAtom>(target))
+      return true;
+    // Accesses to interposable symbols in same linkage unit must also go
+    // through GOT.
+    const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+    if (defTarget != nullptr &&
+        defTarget->interposable() != DefinedAtom::interposeNo) {
+      assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+      return true;
+    }
+    // Target does not require indirection.  So, if instruction allows GOT to be
+    // by-passed, do that optimization and don't create GOT entry.
+    return !canBypassGOT;
+  }
+
+  const DefinedAtom *makeGOTEntry(const Atom *target) {
+    auto pos = _targetToGOT.find(target);
+    if (pos == _targetToGOT.end()) {
+      auto *gotEntry = new (_file.allocator())
+          GOTEntryAtom(_file, _ctx.is64Bit(), target->name());
+      _targetToGOT[target] = gotEntry;
+      const ArchHandler::ReferenceInfo &nlInfo = _archHandler.stubInfo().
+                                                nonLazyPointerReferenceToBinder;
+      gotEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+                             nlInfo.kind, 0, target, 0);
+      return gotEntry;
+    }
+    return pos->second;
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler                             &_archHandler;
+  MachOFile                                       &_file;
+  llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
+};
+
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  assert(ctx.needsGOTPass());
+  pm.add(llvm::make_unique<GOTPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
new file mode 100644 (file)
index 0000000..7bca07e
--- /dev/null
@@ -0,0 +1,489 @@
+//===-- ReaderWriter/MachO/LayoutPass.cpp - Layout atoms ------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LayoutPass.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
+#include <algorithm>
+#include <set>
+#include <utility>
+
+using namespace lld;
+
+#define DEBUG_TYPE "LayoutPass"
+
+namespace lld {
+namespace mach_o {
+
+static bool compareAtoms(const LayoutPass::SortKey &,
+                         const LayoutPass::SortKey &,
+                         LayoutPass::SortOverride customSorter);
+
+#ifndef NDEBUG
+// Return "reason (leftval, rightval)"
+static std::string formatReason(StringRef reason, int leftVal, int rightVal) {
+  return (Twine(reason) + " (" + Twine(leftVal) + ", " + Twine(rightVal) + ")")
+      .str();
+}
+
+// Less-than relationship of two atoms must be transitive, which is, if a < b
+// and b < c, a < c must be true. This function checks the transitivity by
+// checking the sort results.
+static void checkTransitivity(std::vector<LayoutPass::SortKey> &vec,
+                              LayoutPass::SortOverride customSorter) {
+  for (auto i = vec.begin(), e = vec.end(); (i + 1) != e; ++i) {
+    for (auto j = i + 1; j != e; ++j) {
+      assert(compareAtoms(*i, *j, customSorter));
+      assert(!compareAtoms(*j, *i, customSorter));
+    }
+  }
+}
+
+// Helper functions to check follow-on graph.
+typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
+
+static std::string atomToDebugString(const Atom *atom) {
+  const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
+  std::string str;
+  llvm::raw_string_ostream s(str);
+  if (definedAtom->name().empty())
+    s << "<anonymous " << definedAtom << ">";
+  else
+    s << definedAtom->name();
+  s << " in ";
+  if (definedAtom->customSectionName().empty())
+    s << "<anonymous>";
+  else
+    s << definedAtom->customSectionName();
+  s.flush();
+  return str;
+}
+
+static void showCycleDetectedError(const Registry &registry,
+                                   AtomToAtomT &followOnNexts,
+                                   const DefinedAtom *atom) {
+  const DefinedAtom *start = atom;
+  llvm::dbgs() << "There's a cycle in a follow-on chain!\n";
+  do {
+    llvm::dbgs() << "  " << atomToDebugString(atom) << "\n";
+    for (const Reference *ref : *atom) {
+      StringRef kindValStr;
+      if (!registry.referenceKindToString(ref->kindNamespace(), ref->kindArch(),
+                                          ref->kindValue(), kindValStr)) {
+        kindValStr = "<unknown>";
+      }
+      llvm::dbgs() << "    " << kindValStr
+                   << ": " << atomToDebugString(ref->target()) << "\n";
+    }
+    atom = followOnNexts[atom];
+  } while (atom != start);
+  llvm::report_fatal_error("Cycle detected");
+}
+
+/// Exit if there's a cycle in a followon chain reachable from the
+/// given root atom. Uses the tortoise and hare algorithm to detect a
+/// cycle.
+static void checkNoCycleInFollowonChain(const Registry &registry,
+                                        AtomToAtomT &followOnNexts,
+                                        const DefinedAtom *root) {
+  const DefinedAtom *tortoise = root;
+  const DefinedAtom *hare = followOnNexts[root];
+  while (true) {
+    if (!tortoise || !hare)
+      return;
+    if (tortoise == hare)
+      showCycleDetectedError(registry, followOnNexts, tortoise);
+    tortoise = followOnNexts[tortoise];
+    hare = followOnNexts[followOnNexts[hare]];
+  }
+}
+
+static void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
+                                      const DefinedAtom *atom) {
+  if (!atom) return;
+  auto i = followOnRoots.find(atom);
+  if (i == followOnRoots.end()) {
+    llvm_unreachable(((Twine("Atom <") + atomToDebugString(atom) +
+                       "> has no follow-on root!"))
+                         .str()
+                         .c_str());
+  }
+  const DefinedAtom *ap = i->second;
+  while (true) {
+    const DefinedAtom *next = followOnRoots[ap];
+    if (!next) {
+      llvm_unreachable((Twine("Atom <" + atomToDebugString(atom) +
+                              "> is not reachable from its root!"))
+                           .str()
+                           .c_str());
+    }
+    if (next == ap)
+      return;
+    ap = next;
+  }
+}
+
+static void printDefinedAtoms(const File::AtomRange<DefinedAtom> &atomRange) {
+  for (const DefinedAtom *atom : atomRange) {
+    llvm::dbgs() << "  file=" << atom->file().path()
+                 << ", name=" << atom->name()
+                 << ", size=" << atom->size()
+                 << ", type=" << atom->contentType()
+                 << ", ordinal=" << atom->ordinal()
+                 << "\n";
+  }
+}
+
+/// Verify that the followon chain is sane. Should not be called in
+/// release binary.
+void LayoutPass::checkFollowonChain(const File::AtomRange<DefinedAtom> &range) {
+  ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
+
+  // Verify that there's no cycle in follow-on chain.
+  std::set<const DefinedAtom *> roots;
+  for (const auto &ai : _followOnRoots)
+    roots.insert(ai.second);
+  for (const DefinedAtom *root : roots)
+    checkNoCycleInFollowonChain(_registry, _followOnNexts, root);
+
+  // Verify that all the atoms in followOnNexts have references to
+  // their roots.
+  for (const auto &ai : _followOnNexts) {
+    checkReachabilityFromRoot(_followOnRoots, ai.first);
+    checkReachabilityFromRoot(_followOnRoots, ai.second);
+  }
+}
+#endif // #ifndef NDEBUG
+
+/// The function compares atoms by sorting atoms in the following order
+/// a) Sorts atoms by their ordinal overrides (layout-after/ingroup)
+/// b) Sorts atoms by their permissions
+/// c) Sorts atoms by their content
+/// d) Sorts atoms by custom sorter
+/// e) Sorts atoms on how they appear using File Ordinality
+/// f) Sorts atoms on how they appear within the File
+static bool compareAtomsSub(const LayoutPass::SortKey &lc,
+                            const LayoutPass::SortKey &rc,
+                            LayoutPass::SortOverride customSorter,
+                            std::string &reason) {
+  const DefinedAtom *left = lc._atom.get();
+  const DefinedAtom *right = rc._atom.get();
+  if (left == right) {
+    reason = "same";
+    return false;
+  }
+
+  // Find the root of the chain if it is a part of a follow-on chain.
+  const DefinedAtom *leftRoot = lc._root;
+  const DefinedAtom *rightRoot = rc._root;
+
+  // Sort atoms by their ordinal overrides only if they fall in the same
+  // chain.
+  if (leftRoot == rightRoot) {
+    DEBUG(reason = formatReason("override", lc._override, rc._override));
+    return lc._override < rc._override;
+  }
+
+  // Sort same permissions together.
+  DefinedAtom::ContentPermissions leftPerms = leftRoot->permissions();
+  DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
+
+  if (leftPerms != rightPerms) {
+    DEBUG(reason =
+              formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
+    return leftPerms < rightPerms;
+  }
+
+  // Sort same content types together.
+  DefinedAtom::ContentType leftType = leftRoot->contentType();
+  DefinedAtom::ContentType rightType = rightRoot->contentType();
+
+  if (leftType != rightType) {
+    DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType));
+    return leftType < rightType;
+  }
+
+  // Use custom sorter if supplied.
+  if (customSorter) {
+    bool leftBeforeRight;
+    if (customSorter(leftRoot, rightRoot, leftBeforeRight))
+      return leftBeforeRight;
+  }
+
+  // Sort by .o order.
+  const File *leftFile = &leftRoot->file();
+  const File *rightFile = &rightRoot->file();
+
+  if (leftFile != rightFile) {
+    DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
+                                (int)rightFile->ordinal()));
+    return leftFile->ordinal() < rightFile->ordinal();
+  }
+
+  // Sort by atom order with .o file.
+  uint64_t leftOrdinal = leftRoot->ordinal();
+  uint64_t rightOrdinal = rightRoot->ordinal();
+
+  if (leftOrdinal != rightOrdinal) {
+    DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
+                                (int)rightRoot->ordinal()));
+    return leftOrdinal < rightOrdinal;
+  }
+
+  llvm::errs() << "Unordered: <" << left->name() << "> <"
+               << right->name() << ">\n";
+  llvm_unreachable("Atoms with Same Ordinal!");
+}
+
+static bool compareAtoms(const LayoutPass::SortKey &lc,
+                         const LayoutPass::SortKey &rc,
+                         LayoutPass::SortOverride customSorter) {
+  std::string reason;
+  bool result = compareAtomsSub(lc, rc, customSorter, reason);
+  DEBUG({
+    StringRef comp = result ? "<" : ">=";
+    llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
+                 << "' " << comp << " '"
+                 << rc._atom.get()->name() << "' (" << reason << ")\n";
+  });
+  return result;
+}
+
+LayoutPass::LayoutPass(const Registry &registry, SortOverride sorter)
+    : _registry(registry), _customSorter(std::move(sorter)) {}
+
+// Returns the atom immediately followed by the given atom in the followon
+// chain.
+const DefinedAtom *LayoutPass::findAtomFollowedBy(
+    const DefinedAtom *targetAtom) {
+  // Start from the beginning of the chain and follow the chain until
+  // we find the targetChain.
+  const DefinedAtom *atom = _followOnRoots[targetAtom];
+  while (true) {
+    const DefinedAtom *prevAtom = atom;
+    AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
+    // The target atom must be in the chain of its root.
+    assert(targetFollowOnAtomsIter != _followOnNexts.end());
+    atom = targetFollowOnAtomsIter->second;
+    if (atom == targetAtom)
+      return prevAtom;
+  }
+}
+
+// Check if all the atoms followed by the given target atom are of size zero.
+// When this method is called, an atom being added is not of size zero and
+// will be added to the head of the followon chain. All the atoms between the
+// atom and the targetAtom (specified by layout-after) need to be of size zero
+// in this case. Otherwise the desired layout is impossible.
+bool LayoutPass::checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom) {
+  const DefinedAtom *atom = _followOnRoots[targetAtom];
+  while (true) {
+    if (atom == targetAtom)
+      return true;
+    if (atom->size() != 0)
+      // TODO: print warning that an impossible layout is being desired by the
+      // user.
+      return false;
+    AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
+    // The target atom must be in the chain of its root.
+    assert(targetFollowOnAtomsIter != _followOnNexts.end());
+    atom = targetFollowOnAtomsIter->second;
+  }
+}
+
+// Set the root of all atoms in targetAtom's chain to the given root.
+void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
+                              const DefinedAtom *root) {
+  // Walk through the followon chain and override each node's root.
+  while (true) {
+    _followOnRoots[targetAtom] = root;
+    AtomToAtomT::iterator targetFollowOnAtomsIter =
+        _followOnNexts.find(targetAtom);
+    if (targetFollowOnAtomsIter == _followOnNexts.end())
+      return;
+    targetAtom = targetFollowOnAtomsIter->second;
+  }
+}
+
+/// This pass builds the followon tables described by two DenseMaps
+/// followOnRoots and followonNexts.
+/// The followOnRoots map contains a mapping of a DefinedAtom to its root
+/// The followOnNexts map contains a mapping of what DefinedAtom follows the
+/// current Atom
+/// The algorithm follows a very simple approach
+/// a) If the atom is first seen, then make that as the root atom
+/// b) The targetAtom which this Atom contains, has the root thats set to the
+///    root of the current atom
+/// c) If the targetAtom is part of a different tree and the root of the
+///    targetAtom is itself, Chain all the atoms that are contained in the tree
+///    to the current Tree
+/// d) If the targetAtom is part of a different chain and the root of the
+///    targetAtom until the targetAtom has all atoms of size 0, then chain the
+///    targetAtoms and its tree to the current chain
+void LayoutPass::buildFollowOnTable(const File::AtomRange<DefinedAtom> &range) {
+  ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
+  // Set the initial size of the followon and the followonNext hash to the
+  // number of atoms that we have.
+  _followOnRoots.reserve(range.size());
+  _followOnNexts.reserve(range.size());
+  for (const DefinedAtom *ai : range) {
+    for (const Reference *r : *ai) {
+      if (r->kindNamespace() != lld::Reference::KindNamespace::all ||
+          r->kindValue() != lld::Reference::kindLayoutAfter)
+        continue;
+      const DefinedAtom *targetAtom = dyn_cast<DefinedAtom>(r->target());
+      _followOnNexts[ai] = targetAtom;
+
+      // If we find a followon for the first time, let's make that atom as the
+      // root atom.
+      if (_followOnRoots.count(ai) == 0)
+        _followOnRoots[ai] = ai;
+
+      auto iter = _followOnRoots.find(targetAtom);
+      if (iter == _followOnRoots.end()) {
+        // If the targetAtom is not a root of any chain, let's make the root of
+        // the targetAtom to the root of the current chain.
+
+        // The expression m[i] = m[j] where m is a DenseMap and i != j is not
+        // safe. m[j] returns a reference, which would be invalidated when a
+        // rehashing occurs. If rehashing occurs to make room for m[i], m[j]
+        // becomes invalid, and that invalid reference would be used as the RHS
+        // value of the expression.
+        // Copy the value to workaround.
+        const DefinedAtom *tmp = _followOnRoots[ai];
+        _followOnRoots[targetAtom] = tmp;
+        continue;
+      }
+      if (iter->second == targetAtom) {
+        // If the targetAtom is the root of a chain, the chain becomes part of
+        // the current chain. Rewrite the subchain's root to the current
+        // chain's root.
+        setChainRoot(targetAtom, _followOnRoots[ai]);
+        continue;
+      }
+      // The targetAtom is already a part of a chain. If the current atom is
+      // of size zero, we can insert it in the middle of the chain just
+      // before the target atom, while not breaking other atom's followon
+      // relationships. If it's not, we can only insert the current atom at
+      // the beginning of the chain. All the atoms followed by the target
+      // atom must be of size zero in that case to satisfy the followon
+      // relationships.
+      size_t currentAtomSize = ai->size();
+      if (currentAtomSize == 0) {
+        const DefinedAtom *targetPrevAtom = findAtomFollowedBy(targetAtom);
+        _followOnNexts[targetPrevAtom] = ai;
+        const DefinedAtom *tmp = _followOnRoots[targetPrevAtom];
+        _followOnRoots[ai] = tmp;
+        continue;
+      }
+      if (!checkAllPrevAtomsZeroSize(targetAtom))
+        break;
+      _followOnNexts[ai] = _followOnRoots[targetAtom];
+      setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
+    }
+  }
+}
+
+/// Build an ordinal override map by traversing the followon chain, and
+/// assigning ordinals to each atom, if the atoms have their ordinals
+/// already assigned skip the atom and move to the next. This is the
+/// main map thats used to sort the atoms while comparing two atoms together
+void
+LayoutPass::buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range) {
+  ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
+  uint64_t index = 0;
+  for (const DefinedAtom *ai : range) {
+    const DefinedAtom *atom = ai;
+    if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
+      continue;
+    AtomToAtomT::iterator start = _followOnRoots.find(atom);
+    if (start == _followOnRoots.end())
+      continue;
+    for (const DefinedAtom *nextAtom = start->second; nextAtom;
+         nextAtom = _followOnNexts[nextAtom]) {
+      AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
+      if (pos == _ordinalOverrideMap.end())
+        _ordinalOverrideMap[nextAtom] = index++;
+    }
+  }
+}
+
+std::vector<LayoutPass::SortKey>
+LayoutPass::decorate(File::AtomRange<DefinedAtom> &atomRange) const {
+  std::vector<SortKey> ret;
+  for (OwningAtomPtr<DefinedAtom> &atom : atomRange.owning_ptrs()) {
+    auto ri = _followOnRoots.find(atom.get());
+    auto oi = _ordinalOverrideMap.find(atom.get());
+    const auto *root = (ri == _followOnRoots.end()) ? atom.get() : ri->second;
+    uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second;
+    ret.push_back(SortKey(std::move(atom), root, override));
+  }
+  return ret;
+}
+
+void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange,
+                            std::vector<SortKey> &keys) const {
+  size_t i = 0;
+  for (SortKey &k : keys)
+    atomRange[i++] = std::move(k._atom);
+}
+
+/// Perform the actual pass
+llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
+  DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
+  // sort the atoms
+  ScopedTask task(getDefaultDomain(), "LayoutPass");
+  File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
+
+  // Build follow on tables
+  buildFollowOnTable(atomRange);
+
+  // Check the structure of followon graph if running in debug mode.
+  DEBUG(checkFollowonChain(atomRange));
+
+  // Build override maps
+  buildOrdinalOverrideMap(atomRange);
+
+  DEBUG({
+    llvm::dbgs() << "unsorted atoms:\n";
+    printDefinedAtoms(atomRange);
+  });
+
+  std::vector<LayoutPass::SortKey> vec = decorate(atomRange);
+  sort(llvm::parallel::par, vec.begin(), vec.end(),
+       [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
+         return compareAtoms(l, r, _customSorter);
+       });
+  DEBUG(checkTransitivity(vec, _customSorter));
+  undecorate(atomRange, vec);
+
+  DEBUG({
+    llvm::dbgs() << "sorted atoms:\n";
+    printDefinedAtoms(atomRange);
+  });
+
+  DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
+  return llvm::Error::success();
+}
+
+void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(llvm::make_unique<LayoutPass>(
+      ctx.registry(), [&](const DefinedAtom * left, const DefinedAtom * right,
+                          bool & leftBeforeRight) ->bool {
+    return ctx.customAtomOrderer(left, right, leftBeforeRight);
+  }));
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/LayoutPass.h b/lib/ReaderWriter/MachO/LayoutPass.h
new file mode 100644 (file)
index 0000000..c18777e
--- /dev/null
@@ -0,0 +1,119 @@
+//===------ lib/ReaderWriter/MachO/LayoutPass.h - Handles Layout of atoms -===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
+#define LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
+
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace lld {
+class DefinedAtom;
+class SimpleFile;
+
+namespace mach_o {
+
+/// This linker pass does the layout of the atoms. The pass is done after the
+/// order their .o files were found on the command line, then by order of the
+/// atoms (address) in the .o file.  But some atoms have a preferred location
+/// in their section (such as pinned to the start or end of the section), so
+/// the sort must take that into account too.
+class LayoutPass : public Pass {
+public:
+  struct SortKey {
+    SortKey(OwningAtomPtr<DefinedAtom> &&atom,
+            const DefinedAtom *root, uint64_t override)
+    : _atom(std::move(atom)), _root(root), _override(override) {}
+    OwningAtomPtr<DefinedAtom> _atom;
+    const DefinedAtom *_root;
+    uint64_t _override;
+
+    // Note, these are only here to appease MSVC bots which didn't like
+    // the same methods being implemented/deleted in OwningAtomPtr.
+    SortKey(SortKey &&key) : _atom(std::move(key._atom)), _root(key._root),
+                             _override(key._override) {
+      key._root = nullptr;
+    }
+
+    SortKey &operator=(SortKey &&key) {
+      _atom = std::move(key._atom);
+      _root = key._root;
+      key._root = nullptr;
+      _override = key._override;
+      return *this;
+    }
+
+  private:
+    SortKey(const SortKey &) = delete;
+    void operator=(const SortKey&) = delete;
+  };
+
+  typedef std::function<bool (const DefinedAtom *left, const DefinedAtom *right,
+                              bool &leftBeforeRight)> SortOverride;
+
+  LayoutPass(const Registry &registry, SortOverride sorter);
+
+  /// Sorts atoms in mergedFile by content type then by command line order.
+  llvm::Error perform(SimpleFile &mergedFile) override;
+
+  ~LayoutPass() override = default;
+
+private:
+  // Build the followOn atoms chain as specified by the kindLayoutAfter
+  // reference type
+  void buildFollowOnTable(const File::AtomRange<DefinedAtom> &range);
+
+  // Build a map of Atoms to ordinals for sorting the atoms
+  void buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range);
+
+  const Registry &_registry;
+  SortOverride _customSorter;
+
+  typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
+  typedef llvm::DenseMap<const DefinedAtom *, uint64_t> AtomToOrdinalT;
+
+  // A map to be used to sort atoms. It represents the order of atoms in the
+  // result; if Atom X is mapped to atom Y in this map, X will be located
+  // immediately before Y in the output file. Y might be mapped to another
+  // atom, constructing a follow-on chain. An atom cannot be mapped to more
+  // than one atom unless all but one atom are of size zero.
+  AtomToAtomT _followOnNexts;
+
+  // A map to be used to sort atoms. It's a map from an atom to its root of
+  // follow-on chain. A root atom is mapped to itself. If an atom is not in
+  // _followOnNexts, the atom is not in this map, and vice versa.
+  AtomToAtomT _followOnRoots;
+
+  AtomToOrdinalT _ordinalOverrideMap;
+
+  // Helper methods for buildFollowOnTable().
+  const DefinedAtom *findAtomFollowedBy(const DefinedAtom *targetAtom);
+  bool checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom);
+
+  void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
+
+  std::vector<SortKey> decorate(File::AtomRange<DefinedAtom> &atomRange) const;
+
+  void undecorate(File::AtomRange<DefinedAtom> &atomRange,
+                  std::vector<SortKey> &keys) const;
+
+  // Check if the follow-on graph is a correct structure. For debugging only.
+  void checkFollowonChain(const File::AtomRange<DefinedAtom> &range);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
new file mode 100644 (file)
index 0000000..7e7b559
--- /dev/null
@@ -0,0 +1,1102 @@
+//===- lib/ReaderWriter/MachO/MachOLinkingContext.cpp ---------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "ArchHandler.h"
+#include "File.h"
+#include "FlatNamespaceFile.h"
+#include "MachONormalizedFile.h"
+#include "MachOPasses.h"
+#include "SectCreateFile.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+
+using lld::mach_o::ArchHandler;
+using lld::mach_o::MachOFile;
+using lld::mach_o::MachODylibFile;
+using namespace llvm::MachO;
+
+namespace lld {
+
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
+  result = 0;
+
+  if (str.empty())
+    return false;
+
+  SmallVector<StringRef, 3> parts;
+  llvm::SplitString(str, parts, ".");
+
+  unsigned long long num;
+  if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+    return true;
+  if (num > 65535)
+    return true;
+  result = num << 16;
+
+  if (parts.size() > 1) {
+    if (llvm::getAsUnsignedInteger(parts[1], 10, num))
+      return true;
+    if (num > 255)
+      return true;
+    result |= (num << 8);
+  }
+
+  if (parts.size() > 2) {
+    if (llvm::getAsUnsignedInteger(parts[2], 10, num))
+      return true;
+    if (num > 255)
+      return true;
+    result |= num;
+  }
+
+  return false;
+}
+
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {
+  result = 0;
+
+  if (str.empty())
+    return false;
+
+  SmallVector<StringRef, 5> parts;
+  llvm::SplitString(str, parts, ".");
+
+  unsigned long long num;
+  if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+    return true;
+  if (num > 0xFFFFFF)
+    return true;
+  result = num << 40;
+
+  unsigned Shift = 30;
+  for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {
+    if (llvm::getAsUnsignedInteger(str, 10, num))
+      return true;
+    if (num > 0x3FF)
+      return true;
+    result |= (num << Shift);
+    Shift -= 10;
+  }
+
+  return false;
+}
+
+MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
+  { "x86_64", arch_x86_64, true,  CPU_TYPE_X86_64,  CPU_SUBTYPE_X86_64_ALL },
+  { "i386",   arch_x86,    true,  CPU_TYPE_I386,    CPU_SUBTYPE_X86_ALL },
+  { "ppc",    arch_ppc,    false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL },
+  { "armv6",  arch_armv6,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V6 },
+  { "armv7",  arch_armv7,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7 },
+  { "armv7s", arch_armv7s, true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7S },
+  { "arm64",  arch_arm64,  true,  CPU_TYPE_ARM64,   CPU_SUBTYPE_ARM64_ALL },
+  { "",       arch_unknown,false, 0,                0 }
+};
+
+MachOLinkingContext::Arch
+MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))
+      return info->arch;
+  }
+  return arch_unknown;
+}
+
+MachOLinkingContext::Arch
+MachOLinkingContext::archFromName(StringRef archName) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->archName.equals(archName))
+      return info->arch;
+  }
+  return arch_unknown;
+}
+
+StringRef MachOLinkingContext::nameFromArch(Arch arch) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
+      return info->archName;
+  }
+  return "<unknown>";
+}
+
+uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
+      return info->cputype;
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
+      return info->cpusubtype;
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::isThinObjectFile(StringRef path, Arch &arch) {
+  return mach_o::normalized::isThinObjectFile(path, arch);
+}
+
+bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset,
+                                           uint32_t &size) {
+  return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size);
+}
+
+MachOLinkingContext::MachOLinkingContext() {}
+
+MachOLinkingContext::~MachOLinkingContext() {
+  // Atoms are allocated on BumpPtrAllocator's on File's.
+  // As we transfer atoms from one file to another, we need to clear all of the
+  // atoms before we remove any of the BumpPtrAllocator's.
+  auto &nodes = getNodes();
+  for (unsigned i = 0, e = nodes.size(); i != e; ++i) {
+    FileNode *node = dyn_cast<FileNode>(nodes[i].get());
+    if (!node)
+      continue;
+    File *file = node->getFile();
+    file->clearAtoms();
+  }
+}
+
+void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
+                                    uint32_t minOSVersion,
+                                    bool exportDynamicSymbols) {
+  _outputMachOType = type;
+  _arch = arch;
+  _os = os;
+  _osMinVersion = minOSVersion;
+
+  // If min OS not specified on command line, use reasonable defaults.
+  // Note that we only do sensible defaults when emitting something other than
+  // object and preload.
+  if (_outputMachOType != llvm::MachO::MH_OBJECT &&
+      _outputMachOType != llvm::MachO::MH_PRELOAD) {
+    if (minOSVersion == 0) {
+      switch (_arch) {
+      case arch_x86_64:
+      case arch_x86:
+        parsePackedVersion("10.8", _osMinVersion);
+        _os = MachOLinkingContext::OS::macOSX;
+        break;
+      case arch_armv6:
+      case arch_armv7:
+      case arch_armv7s:
+      case arch_arm64:
+        parsePackedVersion("7.0", _osMinVersion);
+        _os = MachOLinkingContext::OS::iOS;
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+  switch (_outputMachOType) {
+  case llvm::MachO::MH_EXECUTE:
+    // If targeting newer OS, use _main
+    if (minOS("10.8", "6.0")) {
+      _entrySymbolName = "_main";
+    } else {
+      // If targeting older OS, use start (in crt1.o)
+      _entrySymbolName = "start";
+    }
+
+    // __PAGEZERO defaults to 4GB on 64-bit (except for PP64 which lld does not
+    // support) and 4KB on 32-bit.
+    if (is64Bit(_arch)) {
+      _pageZeroSize = 0x100000000;
+    } else {
+      _pageZeroSize = 0x1000;
+    }
+
+    // Initial base address is __PAGEZERO size.
+    _baseAddress = _pageZeroSize;
+
+    // Make PIE by default when targetting newer OSs.
+    switch (os) {
+      case OS::macOSX:
+        if (minOSVersion >= 0x000A0700) // MacOSX 10.7
+          _pie = true;
+        break;
+      case OS::iOS:
+        if (minOSVersion >= 0x00040300) // iOS 4.3
+          _pie = true;
+       break;
+       case OS::iOS_simulator:
+        _pie = true;
+       break;
+       case OS::unknown:
+       break;
+    }
+    setGlobalsAreDeadStripRoots(exportDynamicSymbols);
+    break;
+  case llvm::MachO::MH_DYLIB:
+    setGlobalsAreDeadStripRoots(exportDynamicSymbols);
+    break;
+  case llvm::MachO::MH_BUNDLE:
+    break;
+  case llvm::MachO::MH_OBJECT:
+    _printRemainingUndefines = false;
+    _allowRemainingUndefines = true;
+  default:
+    break;
+  }
+
+  // Set default segment page sizes based on arch.
+  if (arch == arch_arm64)
+    _pageSize = 4*4096;
+}
+
+uint32_t MachOLinkingContext::getCPUType() const {
+  return cpuTypeFromArch(_arch);
+}
+
+uint32_t MachOLinkingContext::getCPUSubType() const {
+  return cpuSubtypeFromArch(_arch);
+}
+
+bool MachOLinkingContext::is64Bit(Arch arch) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return (info->cputype & CPU_ARCH_ABI64);
+    }
+  }
+  // unknown archs are not 64-bit.
+  return false;
+}
+
+bool MachOLinkingContext::isHostEndian(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return (info->littleEndian == llvm::sys::IsLittleEndianHost);
+    }
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::isBigEndian(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return ! info->littleEndian;
+    }
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::is64Bit() const {
+  return is64Bit(_arch);
+}
+
+bool MachOLinkingContext::outputTypeHasEntry() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+  case MH_DYLINKER:
+  case MH_PRELOAD:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsStubsPass() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+    return !_outputMachOTypeStatic;
+  case MH_DYLIB:
+  case MH_BUNDLE:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsGOTPass() const {
+  // GOT pass not used in -r mode.
+  if (_outputMachOType == MH_OBJECT)
+    return false;
+  // Only some arches use GOT pass.
+  switch (_arch) {
+    case arch_x86_64:
+    case arch_arm64:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool MachOLinkingContext::needsCompactUnwindPass() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+  case MH_DYLIB:
+  case MH_BUNDLE:
+    return archHandler().needsCompactUnwind();
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsObjCPass() const {
+  // ObjC pass is only needed if any of the inputs were ObjC.
+  return _objcConstraint != objc_unknown;
+}
+
+bool MachOLinkingContext::needsShimPass() const {
+  // Shim pass only used in final executables.
+  if (_outputMachOType == MH_OBJECT)
+    return false;
+  // Only 32-bit arm arches use Shim pass.
+  switch (_arch) {
+  case arch_armv6:
+  case arch_armv7:
+  case arch_armv7s:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsTLVPass() const {
+  switch (_outputMachOType) {
+  case MH_BUNDLE:
+  case MH_EXECUTE:
+  case MH_DYLIB:
+    return true;
+  default:
+    return false;
+  }
+}
+
+StringRef MachOLinkingContext::binderSymbolName() const {
+  return archHandler().stubInfo().binderSymbolName;
+}
+
+bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
+  uint32_t parsedVersion;
+  switch (_os) {
+  case OS::macOSX:
+    if (parsePackedVersion(mac, parsedVersion))
+      return false;
+    return _osMinVersion >= parsedVersion;
+  case OS::iOS:
+  case OS::iOS_simulator:
+    if (parsePackedVersion(iOS, parsedVersion))
+      return false;
+    return _osMinVersion >= parsedVersion;
+  case OS::unknown:
+    // If we don't know the target, then assume that we don't meet the min OS.
+    // This matches the ld64 behaviour
+    return false;
+  }
+  llvm_unreachable("invalid OS enum");
+}
+
+bool MachOLinkingContext::addEntryPointLoadCommand() const {
+  if ((_outputMachOType == MH_EXECUTE) && !_outputMachOTypeStatic) {
+    return minOS("10.8", "6.0");
+  }
+  return false;
+}
+
+bool MachOLinkingContext::addUnixThreadLoadCommand() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+    if (_outputMachOTypeStatic)
+      return true;
+    else
+      return !minOS("10.8", "6.0");
+    break;
+  case MH_DYLINKER:
+  case MH_PRELOAD:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::pathExists(StringRef path) const {
+  if (!_testingFileUsage)
+    return llvm::sys::fs::exists(path.str());
+
+  // Otherwise, we're in test mode: only files explicitly provided on the
+  // command-line exist.
+  std::string key = path.str();
+  std::replace(key.begin(), key.end(), '\\', '/');
+  return _existingPaths.find(key) != _existingPaths.end();
+}
+
+bool MachOLinkingContext::fileExists(StringRef path) const {
+  bool found = pathExists(path);
+  // Log search misses.
+  if (!found)
+    addInputFileNotFound(path);
+
+  // When testing, file is never opened, so logging is done here.
+  if (_testingFileUsage && found)
+    addInputFileDependency(path);
+
+  return found;
+}
+
+void MachOLinkingContext::setSysLibRoots(const StringRefVector &paths) {
+  _syslibRoots = paths;
+}
+
+void MachOLinkingContext::addRpath(StringRef rpath) {
+  _rpaths.push_back(rpath);
+}
+
+void MachOLinkingContext::addModifiedSearchDir(StringRef libPath,
+                                               bool isSystemPath) {
+  bool addedModifiedPath = false;
+
+  // -syslibroot only applies to absolute paths.
+  if (libPath.startswith("/")) {
+    for (auto syslibRoot : _syslibRoots) {
+      SmallString<256> path(syslibRoot);
+      llvm::sys::path::append(path, libPath);
+      if (pathExists(path)) {
+        _searchDirs.push_back(path.str().copy(_allocator));
+        addedModifiedPath = true;
+      }
+    }
+  }
+
+  if (addedModifiedPath)
+    return;
+
+  // Finally, if only one -syslibroot is given, system paths which aren't in it
+  // get suppressed.
+  if (_syslibRoots.size() != 1 || !isSystemPath) {
+    if (pathExists(libPath)) {
+      _searchDirs.push_back(libPath);
+    }
+  }
+}
+
+void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
+                                                bool isSystemPath) {
+  bool pathAdded = false;
+
+  // -syslibroot only used with to absolute framework search paths.
+  if (fwPath.startswith("/")) {
+    for (auto syslibRoot : _syslibRoots) {
+      SmallString<256> path(syslibRoot);
+      llvm::sys::path::append(path, fwPath);
+      if (pathExists(path)) {
+        _frameworkDirs.push_back(path.str().copy(_allocator));
+        pathAdded = true;
+      }
+    }
+  }
+  // If fwPath found in any -syslibroot, then done.
+  if (pathAdded)
+    return;
+
+  // If only one -syslibroot, system paths not in that SDK are suppressed.
+  if (isSystemPath && (_syslibRoots.size() == 1))
+    return;
+
+  // Only use raw fwPath if that directory exists.
+  if (pathExists(fwPath))
+    _frameworkDirs.push_back(fwPath);
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::searchDirForLibrary(StringRef path,
+                                         StringRef libName) const {
+  SmallString<256> fullPath;
+  if (libName.endswith(".o")) {
+    // A request ending in .o is special: just search for the file directly.
+    fullPath.assign(path);
+    llvm::sys::path::append(fullPath, libName);
+    if (fileExists(fullPath))
+      return fullPath.str().copy(_allocator);
+    return llvm::None;
+  }
+
+  // Search for dynamic library
+  fullPath.assign(path);
+  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib");
+  if (fileExists(fullPath))
+    return fullPath.str().copy(_allocator);
+
+  // If not, try for a static library
+  fullPath.assign(path);
+  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a");
+  if (fileExists(fullPath))
+    return fullPath.str().copy(_allocator);
+
+  return llvm::None;
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::searchLibrary(StringRef libName) const {
+  SmallString<256> path;
+  for (StringRef dir : searchDirs()) {
+    llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName);
+    if (searchDir)
+      return searchDir;
+  }
+
+  return llvm::None;
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::findPathForFramework(StringRef fwName) const{
+  SmallString<256> fullPath;
+  for (StringRef dir : frameworkDirs()) {
+    fullPath.assign(dir);
+    llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName);
+    if (fileExists(fullPath))
+      return fullPath.str().copy(_allocator);
+  }
+
+  return llvm::None;
+}
+
+bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
+  // TODO: if -arch not specified, look at arch of first .o file.
+
+  if (_currentVersion && _outputMachOType != MH_DYLIB) {
+    diagnostics << "error: -current_version can only be used with dylibs\n";
+    return false;
+  }
+
+  if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {
+    diagnostics
+        << "error: -compatibility_version can only be used with dylibs\n";
+    return false;
+  }
+
+  if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {
+    diagnostics
+        << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
+    return false;
+  }
+
+  if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {
+    diagnostics
+        << "error: -bundle_loader can only be used with Mach-O bundles\n";
+    return false;
+  }
+
+  // If -exported_symbols_list used, all exported symbols must be defined.
+  if (_exportMode == ExportMode::whiteList) {
+    for (const auto &symbol : _exportedSymbols)
+      addInitialUndefinedSymbol(symbol.getKey());
+  }
+
+  // If -dead_strip, set up initial live symbols.
+  if (deadStrip()) {
+    // Entry point is live.
+    if (outputTypeHasEntry())
+      addDeadStripRoot(entrySymbolName());
+    // Lazy binding helper is live.
+    if (needsStubsPass())
+      addDeadStripRoot(binderSymbolName());
+    // If using -exported_symbols_list, make all exported symbols live.
+    if (_exportMode == ExportMode::whiteList) {
+      setGlobalsAreDeadStripRoots(false);
+      for (const auto &symbol : _exportedSymbols)
+        addDeadStripRoot(symbol.getKey());
+    }
+  }
+
+  addOutputFileDependency(outputPath());
+
+  return true;
+}
+
+void MachOLinkingContext::addPasses(PassManager &pm) {
+  // objc pass should be before layout pass.  Otherwise test cases may contain
+  // no atoms which confuses the layout pass.
+  if (needsObjCPass())
+    mach_o::addObjCPass(pm, *this);
+  mach_o::addLayoutPass(pm, *this);
+  if (needsStubsPass())
+    mach_o::addStubsPass(pm, *this);
+  if (needsCompactUnwindPass())
+    mach_o::addCompactUnwindPass(pm, *this);
+  if (needsGOTPass())
+    mach_o::addGOTPass(pm, *this);
+  if (needsTLVPass())
+    mach_o::addTLVPass(pm, *this);
+  if (needsShimPass())
+    mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass.
+}
+
+Writer &MachOLinkingContext::writer() const {
+  if (!_writer)
+    _writer = createWriterMachO(*this);
+  return *_writer;
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MachOLinkingContext::getMemoryBuffer(StringRef path) {
+  addInputFileDependency(path);
+
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
+    MemoryBuffer::getFileOrSTDIN(path);
+  if (std::error_code ec = mbOrErr.getError())
+    return ec;
+  std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());
+
+  // If buffer contains a fat file, find required arch in fat buffer
+  // and switch buffer to point to just that required slice.
+  uint32_t offset;
+  uint32_t size;
+  if (sliceFromFatFile(mb->getMemBufferRef(), offset, size))
+    return MemoryBuffer::getFileSlice(path, size, offset);
+  return std::move(mb);
+}
+
+MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = getMemoryBuffer(path);
+  if (mbOrErr.getError())
+    return nullptr;
+
+  ErrorOr<std::unique_ptr<File>> fileOrErr =
+      registry().loadFile(std::move(mbOrErr.get()));
+  if (!fileOrErr)
+    return nullptr;
+  std::unique_ptr<File> &file = fileOrErr.get();
+  file->parse();
+  MachODylibFile *result = reinterpret_cast<MachODylibFile *>(file.get());
+  // Node object now owned by _indirectDylibs vector.
+  _indirectDylibs.push_back(std::move(file));
+  return result;
+}
+
+MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {
+  // See if already loaded.
+  auto pos = _pathToDylibMap.find(path);
+  if (pos != _pathToDylibMap.end())
+    return pos->second;
+
+  // Search -L paths if of the form "libXXX.dylib"
+  std::pair<StringRef, StringRef> split = path.rsplit('/');
+  StringRef leafName = split.second;
+  if (leafName.startswith("lib") && leafName.endswith(".dylib")) {
+    // FIXME: Need to enhance searchLibrary() to only look for .dylib
+    auto libPath = searchLibrary(leafName);
+    if (libPath)
+      return loadIndirectDylib(libPath.getValue());
+  }
+
+  // Try full path with sysroot.
+  for (StringRef sysPath : _syslibRoots) {
+    SmallString<256> fullPath;
+    fullPath.assign(sysPath);
+    llvm::sys::path::append(fullPath, path);
+    if (pathExists(fullPath))
+      return loadIndirectDylib(fullPath);
+  }
+
+  // Try full path.
+  if (pathExists(path)) {
+    return loadIndirectDylib(path);
+  }
+
+  return nullptr;
+}
+
+uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const {
+  auto pos = _pathToDylibMap.find(installName);
+  if (pos != _pathToDylibMap.end())
+    return pos->second->currentVersion();
+  else
+    return 0x10000; // 1.0
+}
+
+uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
+  auto pos = _pathToDylibMap.find(installName);
+  if (pos != _pathToDylibMap.end())
+    return pos->second->compatVersion();
+  else
+    return 0x10000; // 1.0
+}
+
+void MachOLinkingContext::createImplicitFiles(
+                            std::vector<std::unique_ptr<File> > &result) {
+  // Add indirect dylibs by asking each linked dylib to add its indirects.
+  // Iterate until no more dylibs get loaded.
+  size_t dylibCount = 0;
+  while (dylibCount != _allDylibs.size()) {
+    dylibCount = _allDylibs.size();
+    for (MachODylibFile *dylib : _allDylibs) {
+      dylib->loadReExportedDylibs([this] (StringRef path) -> MachODylibFile* {
+                                  return findIndirectDylib(path); });
+    }
+  }
+
+  // Let writer add output type specific extras.
+  writer().createImplicitFiles(result);
+
+  // If undefinedMode is != error, add a FlatNamespaceFile instance. This will
+  // provide a SharedLibraryAtom for symbols that aren't defined elsewhere.
+  if (undefinedMode() != UndefinedMode::error) {
+    result.emplace_back(new mach_o::FlatNamespaceFile(*this));
+    _flatNamespaceFile = result.back().get();
+  }
+}
+
+void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
+                                        bool upward) const {
+  std::lock_guard<std::mutex> lock(_dylibsMutex);
+
+  if (std::find(_allDylibs.begin(),
+                _allDylibs.end(), dylib) == _allDylibs.end())
+    _allDylibs.push_back(dylib);
+  _pathToDylibMap[dylib->installName()] = dylib;
+  // If path is different than install name, register path too.
+  if (!dylib->path().equals(dylib->installName()))
+    _pathToDylibMap[dylib->path()] = dylib;
+  if (upward)
+    _upwardDylibs.insert(dylib);
+}
+
+bool MachOLinkingContext::isUpwardDylib(StringRef installName) const {
+  for (MachODylibFile *dylib : _upwardDylibs) {
+    if (dylib->installName().equals(installName))
+      return true;
+  }
+  return false;
+}
+
+ArchHandler &MachOLinkingContext::archHandler() const {
+  if (!_archHandler)
+    _archHandler = ArchHandler::create(_arch);
+  return *_archHandler;
+}
+
+void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect,
+                                              uint16_t align) {
+  SectionAlign entry = { seg, sect, align };
+  _sectAligns.push_back(entry);
+}
+
+void MachOLinkingContext::addSectCreateSection(
+                                        StringRef seg, StringRef sect,
+                                        std::unique_ptr<MemoryBuffer> content) {
+
+  if (!_sectCreateFile) {
+    auto sectCreateFile = llvm::make_unique<mach_o::SectCreateFile>();
+    _sectCreateFile = sectCreateFile.get();
+    getNodes().push_back(llvm::make_unique<FileNode>(std::move(sectCreateFile)));
+  }
+
+  assert(_sectCreateFile && "sectcreate file does not exist.");
+  _sectCreateFile->addSection(seg, sect, std::move(content));
+}
+
+bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
+                                         uint16_t &align) const {
+  for (const SectionAlign &entry : _sectAligns) {
+    if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {
+      align = entry.align;
+      return true;
+    }
+  }
+  return false;
+}
+
+void MachOLinkingContext::addExportSymbol(StringRef sym) {
+  // Support old crufty export lists with bogus entries.
+  if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) {
+    llvm::errs() << "warning: ignoring " << sym << " in export list\n";
+    return;
+  }
+  // Only i386 MacOSX uses old ABI, so don't change those.
+  if ((_os != OS::macOSX) || (_arch != arch_x86)) {
+    // ObjC has two differnent ABIs.  Be nice and allow one export list work for
+    // both ABIs by renaming symbols.
+    if (sym.startswith(".objc_class_name_")) {
+      std::string abi2className("_OBJC_CLASS_$_");
+      abi2className += sym.substr(17);
+      _exportedSymbols.insert(copy(abi2className));
+      std::string abi2metaclassName("_OBJC_METACLASS_$_");
+      abi2metaclassName += sym.substr(17);
+      _exportedSymbols.insert(copy(abi2metaclassName));
+      return;
+    }
+  }
+
+  // FIXME: Support wildcards.
+  _exportedSymbols.insert(sym);
+}
+
+bool MachOLinkingContext::exportSymbolNamed(StringRef sym) const {
+  switch (_exportMode) {
+  case ExportMode::globals:
+    llvm_unreachable("exportSymbolNamed() should not be called in this mode");
+    break;
+  case ExportMode::whiteList:
+    return _exportedSymbols.count(sym);
+  case ExportMode::blackList:
+    return !_exportedSymbols.count(sym);
+  }
+  llvm_unreachable("_exportMode unknown enum value");
+}
+
+std::string MachOLinkingContext::demangle(StringRef symbolName) const {
+  // Only try to demangle symbols if -demangle on command line
+  if (!demangleSymbols())
+    return symbolName;
+
+  // Only try to demangle symbols that look like C++ symbols
+  if (!symbolName.startswith("__Z"))
+    return symbolName;
+
+  SmallString<256> symBuff;
+  StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
+  // Mach-O has extra leading underscore that needs to be removed.
+  const char *cstr = nullTermSym.data() + 1;
+  int status;
+  char *demangled = llvm::itaniumDemangle(cstr, nullptr, nullptr, &status);
+  if (demangled) {
+    std::string result(demangled);
+    // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+    free(demangled);
+    return result;
+  }
+
+  return symbolName;
+}
+
+static void addDependencyInfoHelper(llvm::raw_fd_ostream *DepInfo,
+                                    char Opcode, StringRef Path) {
+  if (!DepInfo)
+    return;
+
+  *DepInfo << Opcode;
+  *DepInfo << Path;
+  *DepInfo << '\0';
+}
+
+std::error_code MachOLinkingContext::createDependencyFile(StringRef path) {
+  std::error_code ec;
+  _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(new
+                         llvm::raw_fd_ostream(path, ec, llvm::sys::fs::F_None));
+  if (ec) {
+    _dependencyInfo.reset();
+    return ec;
+  }
+
+  addDependencyInfoHelper(_dependencyInfo.get(), 0x00, "lld" /*FIXME*/);
+  return std::error_code();
+}
+
+void MachOLinkingContext::addInputFileDependency(StringRef path) const {
+  addDependencyInfoHelper(_dependencyInfo.get(), 0x10, path);
+}
+
+void MachOLinkingContext::addInputFileNotFound(StringRef path) const {
+  addDependencyInfoHelper(_dependencyInfo.get(), 0x11, path);
+}
+
+void MachOLinkingContext::addOutputFileDependency(StringRef path) const {
+  addDependencyInfoHelper(_dependencyInfo.get(), 0x40, path);
+}
+
+void MachOLinkingContext::appendOrderedSymbol(StringRef symbol,
+                                              StringRef filename) {
+  // To support sorting static functions which may have the same name in
+  // multiple .o files, _orderFiles maps the symbol name to a vector
+  // of OrderFileNode each of which can specify a file prefix.
+  OrderFileNode info;
+  if (!filename.empty())
+    info.fileFilter = copy(filename);
+  info.order = _orderFileEntries++;
+  _orderFiles[symbol].push_back(info);
+}
+
+bool
+MachOLinkingContext::findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+                                      const DefinedAtom *atom,
+                                      unsigned &ordinal) {
+  const File *objFile = &atom->file();
+  assert(objFile);
+  StringRef objName = objFile->path();
+  std::pair<StringRef, StringRef> dirAndLeaf = objName.rsplit('/');
+  if (!dirAndLeaf.second.empty())
+    objName = dirAndLeaf.second;
+  for (const OrderFileNode &info : nodes) {
+    if (info.fileFilter.empty()) {
+      // Have unprefixed symbol name in order file that matches this atom.
+      ordinal = info.order;
+      return true;
+    }
+    if (info.fileFilter.equals(objName)) {
+      // Have prefixed symbol name in order file that matches atom's path.
+      ordinal = info.order;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,
+                                            const DefinedAtom *right,
+                                            bool &leftBeforeRight) const {
+  // No custom sorting if no order file entries.
+  if (!_orderFileEntries)
+    return false;
+
+  // Order files can only order named atoms.
+  StringRef leftName = left->name();
+  StringRef rightName = right->name();
+  if (leftName.empty() || rightName.empty())
+    return false;
+
+  // If neither is in order file list, no custom sorter.
+  auto leftPos = _orderFiles.find(leftName);
+  auto rightPos = _orderFiles.find(rightName);
+  bool leftIsOrdered = (leftPos != _orderFiles.end());
+  bool rightIsOrdered = (rightPos != _orderFiles.end());
+  if (!leftIsOrdered && !rightIsOrdered)
+    return false;
+
+  // There could be multiple symbols with same name but different file prefixes.
+  unsigned leftOrder;
+  unsigned rightOrder;
+  bool foundLeft =
+      leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder);
+  bool foundRight = rightIsOrdered &&
+                    findOrderOrdinal(rightPos->getValue(), right, rightOrder);
+  if (!foundLeft && !foundRight)
+    return false;
+
+  // If only one is in order file list, ordered one goes first.
+  if (foundLeft != foundRight)
+    leftBeforeRight = foundLeft;
+  else
+    leftBeforeRight = (leftOrder < rightOrder);
+
+  return true;
+}
+
+static bool isLibrary(const std::unique_ptr<Node> &elem) {
+  if (FileNode *node = dyn_cast<FileNode>(const_cast<Node *>(elem.get()))) {
+    File *file = node->getFile();
+    return isa<SharedLibraryFile>(file) || isa<ArchiveLibraryFile>(file);
+  }
+  return false;
+}
+
+// The darwin linker processes input files in two phases.  The first phase
+// links in all object (.o) files in command line order. The second phase
+// links in libraries in command line order.
+// In this function we reorder the input files so that all the object files
+// comes before any library file. We also make a group for the library files
+// so that the Resolver will reiterate over the libraries as long as we find
+// new undefines from libraries.
+void MachOLinkingContext::finalizeInputFiles() {
+  std::vector<std::unique_ptr<Node>> &elements = getNodes();
+  std::stable_sort(elements.begin(), elements.end(),
+                   [](const std::unique_ptr<Node> &a,
+                      const std::unique_ptr<Node> &b) {
+                     return !isLibrary(a) && isLibrary(b);
+                   });
+  size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary);
+  elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
+}
+
+llvm::Error MachOLinkingContext::handleLoadedFile(File &file) {
+  auto *machoFile = dyn_cast<MachOFile>(&file);
+  if (!machoFile)
+    return llvm::Error::success();
+
+  // Check that the arch of the context matches that of the file.
+  // Also set the arch of the context if it didn't have one.
+  if (_arch == arch_unknown) {
+    _arch = machoFile->arch();
+  } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) {
+    // Archs are different.
+    return llvm::make_error<GenericError>(file.path() +
+                  Twine(" cannot be linked due to incompatible architecture"));
+  }
+
+  // Check that the OS of the context matches that of the file.
+  // Also set the OS of the context if it didn't have one.
+  if (_os == OS::unknown) {
+    _os = machoFile->OS();
+  } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) {
+    // OSes are different.
+    return llvm::make_error<GenericError>(file.path() +
+              Twine(" cannot be linked due to incompatible operating systems"));
+  }
+
+  // Check that if the objc info exists, that it is compatible with the target
+  // OS.
+  switch (machoFile->objcConstraint()) {
+    case objc_unknown:
+      // The file is not compiled with objc, so skip the checks.
+      break;
+    case objc_gc_only:
+    case objc_supports_gc:
+      llvm_unreachable("GC support should already have thrown an error");
+    case objc_retainReleaseForSimulator:
+      // The file is built with simulator objc, so make sure that the context
+      // is also building with simulator support.
+      if (_os != OS::iOS_simulator)
+        return llvm::make_error<GenericError>(file.path() +
+          Twine(" cannot be linked.  It contains ObjC built for the simulator"
+                " while we are linking a non-simulator target"));
+      assert((_objcConstraint == objc_unknown ||
+              _objcConstraint == objc_retainReleaseForSimulator) &&
+             "Must be linking with retain/release for the simulator");
+      _objcConstraint = objc_retainReleaseForSimulator;
+      break;
+    case objc_retainRelease:
+      // The file is built without simulator objc, so make sure that the
+      // context is also building without simulator support.
+      if (_os == OS::iOS_simulator)
+        return llvm::make_error<GenericError>(file.path() +
+          Twine(" cannot be linked.  It contains ObjC built for a non-simulator"
+                " target while we are linking a simulator target"));
+      assert((_objcConstraint == objc_unknown ||
+              _objcConstraint == objc_retainRelease) &&
+             "Must be linking with retain/release for a non-simulator target");
+      _objcConstraint = objc_retainRelease;
+      break;
+  }
+
+  // Check that the swift version of the context matches that of the file.
+  // Also set the swift version of the context if it didn't have one.
+  if (!_swiftVersion) {
+    _swiftVersion = machoFile->swiftVersion();
+  } else if (machoFile->swiftVersion() &&
+             machoFile->swiftVersion() != _swiftVersion) {
+    // Swift versions are different.
+    return llvm::make_error<GenericError>("different swift versions");
+  }
+
+  return llvm::Error::success();
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h
new file mode 100644 (file)
index 0000000..31b24df
--- /dev/null
@@ -0,0 +1,345 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFile.h -----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file These data structures comprise the "normalized" view of
+/// mach-o object files. The normalized view is an in-memory only data structure
+/// which is always in native endianness and pointer size.
+///
+/// The normalized view easily converts to and from YAML using YAML I/O.
+///
+/// The normalized view converts to and from binary mach-o object files using
+/// the writeBinary() and readBinary() functions.
+///
+/// The normalized view converts to and from lld::Atoms using the
+/// normalizedToAtoms() and normalizedFromAtoms().
+///
+/// Overall, the conversion paths available look like:
+///
+///                 +---------------+
+///                 | binary mach-o |
+///                 +---------------+
+///                        ^
+///                        |
+///                        v
+///                  +------------+         +------+
+///                  | normalized |   <->   | yaml |
+///                  +------------+         +------+
+///                        ^
+///                        |
+///                        v
+///                    +-------+
+///                    | Atoms |
+///                    +-------+
+///
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+
+#include "DebugInfo.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using llvm::BumpPtrAllocator;
+using llvm::yaml::Hex64;
+using llvm::yaml::Hex32;
+using llvm::yaml::Hex16;
+using llvm::yaml::Hex8;
+using llvm::yaml::SequenceTraits;
+using llvm::MachO::HeaderFileType;
+using llvm::MachO::BindType;
+using llvm::MachO::RebaseType;
+using llvm::MachO::NListType;
+using llvm::MachO::RelocationInfoType;
+using llvm::MachO::SectionType;
+using llvm::MachO::LoadCommandType;
+using llvm::MachO::ExportSymbolKind;
+using llvm::MachO::DataRegionType;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+
+/// The real mach-o relocation record is 8-bytes on disk and is
+/// encoded in one of two different bit-field patterns.  This
+/// normalized form has the union of all possible fields.
+struct Relocation {
+  Relocation() : offset(0), scattered(false),
+                 type(llvm::MachO::GENERIC_RELOC_VANILLA),
+                 length(0), pcRel(false), isExtern(false), value(0),
+                 symbol(0) { }
+
+  Hex32               offset;
+  bool                scattered;
+  RelocationInfoType  type;
+  uint8_t             length;
+  bool                pcRel;
+  bool                isExtern;
+  Hex32               value;
+  uint32_t            symbol;
+};
+
+/// A typedef so that YAML I/O can treat this vector as a sequence.
+typedef std::vector<Relocation> Relocations;
+
+/// A typedef so that YAML I/O can process the raw bytes in a section.
+typedef std::vector<Hex8> ContentBytes;
+
+/// A typedef so that YAML I/O can treat indirect symbols as a flow sequence.
+typedef std::vector<uint32_t> IndirectSymbols;
+
+/// A typedef so that YAML I/O can encode/decode section attributes.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr)
+
+/// A typedef so that YAML I/O can encode/decode section alignment.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SectionAlignment)
+
+/// Mach-O has a 32-bit and 64-bit section record.  This normalized form
+/// can support either kind.
+struct Section {
+  Section() : type(llvm::MachO::S_REGULAR),
+              attributes(0), alignment(1), address(0) { }
+
+  StringRef       segmentName;
+  StringRef       sectionName;
+  SectionType     type;
+  SectionAttr     attributes;
+  SectionAlignment        alignment;
+  Hex64           address;
+  ArrayRef<uint8_t> content;
+  Relocations     relocations;
+  IndirectSymbols indirectSymbols;
+
+#ifndef NDEBUG
+  raw_ostream& operator<<(raw_ostream &OS) const {
+    dump(OS);
+    return OS;
+  }
+
+  void dump(raw_ostream &OS = llvm::dbgs()) const;
+#endif
+};
+
+
+/// A typedef so that YAML I/O can encode/decode the scope bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, SymbolScope)
+
+/// A typedef so that YAML I/O can encode/decode the desc bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SymbolDesc)
+
+/// Mach-O has a 32-bit and 64-bit symbol table entry (nlist), and the symbol
+/// type and scope and mixed in the same n_type field.  This normalized form
+/// works for any pointer size and separates out the type and scope.
+struct Symbol {
+  Symbol() : type(llvm::MachO::N_UNDF), scope(0), sect(0), desc(0), value(0) { }
+
+  StringRef     name;
+  NListType     type;
+  SymbolScope   scope;
+  uint8_t       sect;
+  SymbolDesc    desc;
+  Hex64         value;
+};
+
+/// Check whether the given section type indicates a zero-filled section.
+// FIXME: Utility functions of this kind should probably be moved into
+//        llvm/Support.
+inline bool isZeroFillSection(SectionType T) {
+  return (T == llvm::MachO::S_ZEROFILL ||
+          T == llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+}
+
+/// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect)
+
+/// A typedef to hold verions X.Y.X packed into 32-bit xxxx.yy.zz
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, PackedVersion)
+
+/// Segments are only used in normalized final linked images (not in relocatable
+/// object files). They specify how a range of the file is loaded.
+struct Segment {
+  StringRef     name;
+  Hex64         address;
+  Hex64         size;
+  VMProtect     init_access;
+  VMProtect     max_access;
+};
+
+/// Only used in normalized final linked images to specify on which dylibs
+/// it depends.
+struct DependentDylib {
+  StringRef       path;
+  LoadCommandType kind;
+  PackedVersion   compatVersion;
+  PackedVersion   currentVersion;
+};
+
+/// A normalized rebasing entry.  Only used in normalized final linked images.
+struct RebaseLocation {
+  Hex32         segOffset;
+  uint8_t       segIndex;
+  RebaseType    kind;
+};
+
+/// A normalized binding entry.  Only used in normalized final linked images.
+struct BindLocation {
+  Hex32           segOffset;
+  uint8_t         segIndex;
+  BindType        kind;
+  bool            canBeNull;
+  int             ordinal;
+  StringRef       symbolName;
+  Hex64           addend;
+};
+
+/// A typedef so that YAML I/O can encode/decode export flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, ExportFlags)
+
+/// A normalized export entry.  Only used in normalized final linked images.
+struct Export {
+  StringRef         name;
+  Hex64             offset;
+  ExportSymbolKind  kind;
+  ExportFlags       flags;
+  Hex32             otherOffset;
+  StringRef         otherName;
+};
+
+/// A normalized data-in-code entry.
+struct DataInCode {
+  Hex32           offset;
+  Hex16           length;
+  DataRegionType  kind;
+};
+
+/// A typedef so that YAML I/O can encode/decode mach_header.flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags)
+
+///
+struct NormalizedFile {
+  MachOLinkingContext::Arch   arch = MachOLinkingContext::arch_unknown;
+  HeaderFileType              fileType = llvm::MachO::MH_OBJECT;
+  FileFlags                   flags = 0;
+  std::vector<Segment>        segments; // Not used in object files.
+  std::vector<Section>        sections;
+
+  // Symbols sorted by kind.
+  std::vector<Symbol>         localSymbols;
+  std::vector<Symbol>         globalSymbols;
+  std::vector<Symbol>         undefinedSymbols;
+  std::vector<Symbol>         stabsSymbols;
+
+  // Maps to load commands with no LINKEDIT content (final linked images only).
+  std::vector<DependentDylib> dependentDylibs;
+  StringRef                   installName;        // dylibs only
+  PackedVersion               compatVersion = 0;  // dylibs only
+  PackedVersion               currentVersion = 0; // dylibs only
+  bool                        hasUUID = false;
+  bool                        hasMinVersionLoadCommand = false;
+  bool                        generateDataInCodeLoadCommand = false;
+  std::vector<StringRef>      rpaths;
+  Hex64                       entryAddress = 0;
+  Hex64                       stackSize = 0;
+  MachOLinkingContext::OS     os = MachOLinkingContext::OS::unknown;
+  Hex64                       sourceVersion = 0;
+  PackedVersion               minOSverson = 0;
+  PackedVersion               sdkVersion = 0;
+  LoadCommandType             minOSVersionKind = (LoadCommandType)0;
+
+  // Maps to load commands with LINKEDIT content (final linked images only).
+  Hex32                       pageSize = 0;
+  std::vector<RebaseLocation> rebasingInfo;
+  std::vector<BindLocation>   bindingInfo;
+  std::vector<BindLocation>   weakBindingInfo;
+  std::vector<BindLocation>   lazyBindingInfo;
+  std::vector<Export>         exportInfo;
+  std::vector<uint8_t>        functionStarts;
+  std::vector<DataInCode>     dataInCode;
+
+  // TODO:
+  // code-signature
+  // split-seg-info
+  // function-starts
+
+  // For any allocations in this struct which need to be owned by this struct.
+  BumpPtrAllocator            ownedAllocations;
+};
+
+/// Tests if a file is a non-fat mach-o object file.
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch);
+
+/// If the buffer is a fat file with the request arch, then this function
+/// returns true with 'offset' and 'size' set to location of the arch slice
+/// within the buffer.  Otherwise returns false;
+bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
+                      uint32_t &offset, uint32_t &size);
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readBinary(std::unique_ptr<MemoryBuffer> &mb,
+           const MachOLinkingContext::Arch arch);
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path);
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file);
+
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readYaml(std::unique_ptr<MemoryBuffer> &mb);
+
+/// Writes a yaml encoded mach-o files given an in-memory normalized view.
+std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
+
+llvm::Error
+normalizedObjectToAtoms(MachOFile *file,
+                        const NormalizedFile &normalizedFile,
+                        bool copyRefs);
+
+llvm::Error
+normalizedDylibToAtoms(MachODylibFile *file,
+                       const NormalizedFile &normalizedFile,
+                       bool copyRefs);
+
+/// Takes in-memory normalized dylib or object and parses it into lld::File
+llvm::Expected<std::unique_ptr<lld::File>>
+normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+                  bool copyRefs);
+
+/// Takes atoms and generates a normalized macho-o view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt);
+
+
+} // namespace normalized
+
+/// Class for interfacing mach-o yaml files into generic yaml parsing
+class MachOYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+public:
+  MachOYamlIOTaggedDocumentHandler(MachOLinkingContext::Arch arch)
+    : _arch(arch) { }
+  bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override;
+private:
+  const MachOLinkingContext::Arch _arch;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
new file mode 100644 (file)
index 0000000..b540547
--- /dev/null
@@ -0,0 +1,591 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts from
+/// mach-o on-disk binary format to in-memory normalized mach-o.
+///
+///                 +---------------+
+///                 | binary mach-o |
+///                 +---------------+
+///                        |
+///                        |
+///                        v
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+
+#include "ArchHandler.h"
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <system_error>
+
+using namespace llvm::MachO;
+using llvm::object::ExportEntry;
+using llvm::file_magic;
+using llvm::object::MachOObjectFile;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+// Utility to call a lambda expression on each load command.
+static llvm::Error forEachLoadCommand(
+    StringRef lcRange, unsigned lcCount, bool isBig, bool is64,
+    std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) {
+  const char* p = lcRange.begin();
+  for (unsigned i=0; i < lcCount; ++i) {
+    const load_command *lc = reinterpret_cast<const load_command*>(p);
+    load_command lcCopy;
+    const load_command *slc = lc;
+    if (isBig != llvm::sys::IsBigEndianHost) {
+      memcpy(&lcCopy, lc, sizeof(load_command));
+      swapStruct(lcCopy);
+      slc = &lcCopy;
+    }
+    if ( (p + slc->cmdsize) > lcRange.end() )
+      return llvm::make_error<GenericError>("Load command exceeds range");
+
+    if (func(slc->cmd, slc->cmdsize, p))
+      return llvm::Error::success();
+
+    p += slc->cmdsize;
+  }
+
+  return llvm::Error::success();
+}
+
+static std::error_code appendRelocations(Relocations &relocs, StringRef buffer,
+                                         bool bigEndian,
+                                         uint32_t reloff, uint32_t nreloc) {
+  if ((reloff + nreloc*8) > buffer.size())
+    return make_error_code(llvm::errc::executable_format_error);
+  const any_relocation_info* relocsArray =
+            reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff);
+
+  for(uint32_t i=0; i < nreloc; ++i) {
+    relocs.push_back(unpackRelocation(relocsArray[i], bigEndian));
+  }
+  return std::error_code();
+}
+
+static std::error_code
+appendIndirectSymbols(IndirectSymbols &isyms, StringRef buffer, bool isBig,
+                      uint32_t istOffset, uint32_t istCount,
+                      uint32_t startIndex, uint32_t count) {
+  if ((istOffset + istCount*4) > buffer.size())
+    return make_error_code(llvm::errc::executable_format_error);
+  if (startIndex+count  > istCount)
+    return make_error_code(llvm::errc::executable_format_error);
+  const uint8_t *indirectSymbolArray = (const uint8_t *)buffer.data();
+
+  for(uint32_t i=0; i < count; ++i) {
+    isyms.push_back(read32(
+        indirectSymbolArray + (startIndex + i) * sizeof(uint32_t), isBig));
+  }
+  return std::error_code();
+}
+
+
+template <typename T> static T readBigEndian(T t) {
+  if (llvm::sys::IsLittleEndianHost)
+    llvm::sys::swapByteOrder(t);
+  return t;
+}
+
+
+static bool isMachOHeader(const mach_header *mh, bool &is64, bool &isBig) {
+  switch (read32(&mh->magic, false)) {
+  case llvm::MachO::MH_MAGIC:
+    is64 = false;
+    isBig = false;
+    return true;
+  case llvm::MachO::MH_MAGIC_64:
+    is64 = true;
+    isBig = false;
+    return true;
+  case llvm::MachO::MH_CIGAM:
+    is64 = false;
+    isBig = true;
+    return true;
+  case llvm::MachO::MH_CIGAM_64:
+    is64 = true;
+    isBig = true;
+    return true;
+  default:
+    return false;
+  }
+}
+
+
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) {
+  // Try opening and mapping file at path.
+  ErrorOr<std::unique_ptr<MemoryBuffer>> b = MemoryBuffer::getFileOrSTDIN(path);
+  if (b.getError())
+    return false;
+
+  // If file length < 32 it is too small to be mach-o object file.
+  StringRef fileBuffer = b->get()->getBuffer();
+  if (fileBuffer.size() < 32)
+    return false;
+
+  // If file buffer does not start with MH_MAGIC (and variants), not obj file.
+  const mach_header *mh = reinterpret_cast<const mach_header *>(
+                                                            fileBuffer.begin());
+  bool is64, isBig;
+  if (!isMachOHeader(mh, is64, isBig))
+    return false;
+
+  // If not MH_OBJECT, not object file.
+  if (read32(&mh->filetype, isBig) != MH_OBJECT)
+    return false;
+
+  // Lookup up arch from cpu/subtype pair.
+  arch = MachOLinkingContext::archFromCpuType(
+      read32(&mh->cputype, isBig),
+      read32(&mh->cpusubtype, isBig));
+  return true;
+}
+
+bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
+                      uint32_t &offset, uint32_t &size) {
+  const char *start = mb.getBufferStart();
+  const llvm::MachO::fat_header *fh =
+      reinterpret_cast<const llvm::MachO::fat_header *>(start);
+  if (readBigEndian(fh->magic) != llvm::MachO::FAT_MAGIC)
+    return false;
+  uint32_t nfat_arch = readBigEndian(fh->nfat_arch);
+  const fat_arch *fstart =
+      reinterpret_cast<const fat_arch *>(start + sizeof(fat_header));
+  const fat_arch *fend =
+      reinterpret_cast<const fat_arch *>(start + sizeof(fat_header) +
+                                         sizeof(fat_arch) * nfat_arch);
+  const uint32_t reqCpuType = MachOLinkingContext::cpuTypeFromArch(arch);
+  const uint32_t reqCpuSubtype = MachOLinkingContext::cpuSubtypeFromArch(arch);
+  for (const fat_arch *fa = fstart; fa < fend; ++fa) {
+    if ((readBigEndian(fa->cputype) == reqCpuType) &&
+        (readBigEndian(fa->cpusubtype) == reqCpuSubtype)) {
+      offset = readBigEndian(fa->offset);
+      size = readBigEndian(fa->size);
+      if ((offset + size) > mb.getBufferSize())
+        return false;
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readBinary(std::unique_ptr<MemoryBuffer> &mb,
+           const MachOLinkingContext::Arch arch) {
+  // Make empty NormalizedFile.
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+  const char *start = mb->getBufferStart();
+  size_t objSize = mb->getBufferSize();
+  const mach_header *mh = reinterpret_cast<const mach_header *>(start);
+
+  uint32_t sliceOffset;
+  uint32_t sliceSize;
+  if (sliceFromFatFile(mb->getMemBufferRef(), arch, sliceOffset, sliceSize)) {
+    start = &start[sliceOffset];
+    objSize = sliceSize;
+    mh = reinterpret_cast<const mach_header *>(start);
+  }
+
+  // Determine endianness and pointer size for mach-o file.
+  bool is64, isBig;
+  if (!isMachOHeader(mh, is64, isBig))
+    return llvm::make_error<GenericError>("File is not a mach-o");
+
+  // Endian swap header, if needed.
+  mach_header headerCopy;
+  const mach_header *smh = mh;
+  if (isBig != llvm::sys::IsBigEndianHost) {
+    memcpy(&headerCopy, mh, sizeof(mach_header));
+    swapStruct(headerCopy);
+    smh = &headerCopy;
+  }
+
+  // Validate head and load commands fit in buffer.
+  const uint32_t lcCount = smh->ncmds;
+  const char *lcStart =
+      start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header));
+  StringRef lcRange(lcStart, smh->sizeofcmds);
+  if (lcRange.end() > (start + objSize))
+    return llvm::make_error<GenericError>("Load commands exceed file size");
+
+  // Get architecture from mach_header.
+  f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
+  if (f->arch != arch) {
+    return llvm::make_error<GenericError>(
+                                  Twine("file is wrong architecture. Expected "
+                                  "(" + MachOLinkingContext::nameFromArch(arch)
+                                  + ") found ("
+                                  + MachOLinkingContext::nameFromArch(f->arch)
+                                  + ")" ));
+  }
+  // Copy file type and flags
+  f->fileType = HeaderFileType(smh->filetype);
+  f->flags = smh->flags;
+
+
+  // Pre-scan load commands looking for indirect symbol table.
+  uint32_t indirectSymbolTableOffset = 0;
+  uint32_t indirectSymbolTableCount = 0;
+  auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+                               [&](uint32_t cmd, uint32_t size,
+                                   const char *lc) -> bool {
+    if (cmd == LC_DYSYMTAB) {
+      const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc);
+      indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig);
+      indirectSymbolTableCount = read32(&d->nindirectsyms, isBig);
+      return true;
+    }
+    return false;
+  });
+  if (ec)
+    return std::move(ec);
+
+  // Walk load commands looking for segments/sections and the symbol table.
+  const data_in_code_entry *dataInCode = nullptr;
+  const dyld_info_command *dyldInfo = nullptr;
+  uint32_t dataInCodeSize = 0;
+  ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+                    [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
+    switch(cmd) {
+    case LC_SEGMENT_64:
+      if (is64) {
+        const segment_command_64 *seg =
+                              reinterpret_cast<const segment_command_64*>(lc);
+        const unsigned sectionCount = read32(&seg->nsects, isBig);
+        const section_64 *sects = reinterpret_cast<const section_64*>
+                                  (lc + sizeof(segment_command_64));
+        const unsigned lcSize = sizeof(segment_command_64)
+                                              + sectionCount*sizeof(section_64);
+        // Verify sections don't extend beyond end of segment load command.
+        if (lcSize > size)
+          return true;
+        for (unsigned i=0; i < sectionCount; ++i) {
+          const section_64 *sect = &sects[i];
+          Section section;
+          section.segmentName = getString16(sect->segname);
+          section.sectionName = getString16(sect->sectname);
+          section.type = (SectionType)(read32(&sect->flags, isBig) &
+                                       SECTION_TYPE);
+          section.attributes  = read32(&sect->flags, isBig) & SECTION_ATTRIBUTES;
+          section.alignment   = 1 << read32(&sect->align, isBig);
+          section.address     = read64(&sect->addr, isBig);
+          const uint8_t *content =
+            (const uint8_t *)start + read32(&sect->offset, isBig);
+          size_t contentSize = read64(&sect->size, isBig);
+          // Note: this assign() is copying the content bytes.  Ideally,
+          // we can use a custom allocator for vector to avoid the copy.
+          section.content = llvm::makeArrayRef(content, contentSize);
+          appendRelocations(section.relocations, mb->getBuffer(), isBig,
+                            read32(&sect->reloff, isBig),
+                            read32(&sect->nreloc, isBig));
+          if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
+            appendIndirectSymbols(section.indirectSymbols, mb->getBuffer(),
+                                  isBig,
+                                  indirectSymbolTableOffset,
+                                  indirectSymbolTableCount,
+                                  read32(&sect->reserved1, isBig),
+                                  contentSize/4);
+          }
+          f->sections.push_back(section);
+        }
+      }
+      break;
+    case LC_SEGMENT:
+      if (!is64) {
+        const segment_command *seg =
+                              reinterpret_cast<const segment_command*>(lc);
+        const unsigned sectionCount = read32(&seg->nsects, isBig);
+        const section *sects = reinterpret_cast<const section*>
+                                  (lc + sizeof(segment_command));
+        const unsigned lcSize = sizeof(segment_command)
+                                              + sectionCount*sizeof(section);
+        // Verify sections don't extend beyond end of segment load command.
+        if (lcSize > size)
+          return true;
+        for (unsigned i=0; i < sectionCount; ++i) {
+          const section *sect = &sects[i];
+          Section section;
+          section.segmentName = getString16(sect->segname);
+          section.sectionName = getString16(sect->sectname);
+          section.type = (SectionType)(read32(&sect->flags, isBig) &
+                                       SECTION_TYPE);
+          section.attributes =
+              read32((const uint8_t *)&sect->flags, isBig) & SECTION_ATTRIBUTES;
+          section.alignment   = 1 << read32(&sect->align, isBig);
+          section.address     = read32(&sect->addr, isBig);
+          const uint8_t *content =
+            (const uint8_t *)start + read32(&sect->offset, isBig);
+          size_t contentSize = read32(&sect->size, isBig);
+          // Note: this assign() is copying the content bytes.  Ideally,
+          // we can use a custom allocator for vector to avoid the copy.
+          section.content = llvm::makeArrayRef(content, contentSize);
+          appendRelocations(section.relocations, mb->getBuffer(), isBig,
+                            read32(&sect->reloff, isBig),
+                            read32(&sect->nreloc, isBig));
+          if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
+            appendIndirectSymbols(
+                section.indirectSymbols, mb->getBuffer(), isBig,
+                indirectSymbolTableOffset, indirectSymbolTableCount,
+                read32(&sect->reserved1, isBig), contentSize / 4);
+          }
+          f->sections.push_back(section);
+        }
+      }
+      break;
+    case LC_SYMTAB: {
+      const symtab_command *st = reinterpret_cast<const symtab_command*>(lc);
+      const char *strings = start + read32(&st->stroff, isBig);
+      const uint32_t strSize = read32(&st->strsize, isBig);
+      // Validate string pool and symbol table all in buffer.
+      if (read32((const uint8_t *)&st->stroff, isBig) +
+              read32((const uint8_t *)&st->strsize, isBig) >
+          objSize)
+        return true;
+      if (is64) {
+        const uint32_t symOffset = read32(&st->symoff, isBig);
+        const uint32_t symCount = read32(&st->nsyms, isBig);
+        if ( symOffset+(symCount*sizeof(nlist_64)) > objSize)
+          return true;
+        const nlist_64 *symbols =
+            reinterpret_cast<const nlist_64 *>(start + symOffset);
+        // Convert each nlist_64 to a lld::mach_o::normalized::Symbol.
+        for(uint32_t i=0; i < symCount; ++i) {
+          nlist_64 tempSym;
+          memcpy(&tempSym, &symbols[i], sizeof(nlist_64));
+          const nlist_64 *sin = &tempSym;
+          if (isBig != llvm::sys::IsBigEndianHost)
+            swapStruct(tempSym);
+          Symbol sout;
+          if (sin->n_strx > strSize)
+            return true;
+          sout.name  = &strings[sin->n_strx];
+          sout.type = static_cast<NListType>(sin->n_type & (N_STAB|N_TYPE));
+          sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+          sout.sect  = sin->n_sect;
+          sout.desc  = sin->n_desc;
+          sout.value = sin->n_value;
+          if (sin->n_type & N_STAB)
+            f->stabsSymbols.push_back(sout);
+          else if (sout.type == N_UNDF)
+            f->undefinedSymbols.push_back(sout);
+          else if (sin->n_type & N_EXT)
+            f->globalSymbols.push_back(sout);
+          else
+            f->localSymbols.push_back(sout);
+        }
+      } else {
+        const uint32_t symOffset = read32(&st->symoff, isBig);
+        const uint32_t symCount = read32(&st->nsyms, isBig);
+        if ( symOffset+(symCount*sizeof(nlist)) > objSize)
+          return true;
+        const nlist *symbols =
+            reinterpret_cast<const nlist *>(start + symOffset);
+        // Convert each nlist to a lld::mach_o::normalized::Symbol.
+        for(uint32_t i=0; i < symCount; ++i) {
+          const nlist *sin = &symbols[i];
+          nlist tempSym;
+          if (isBig != llvm::sys::IsBigEndianHost) {
+            tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
+          }
+          Symbol sout;
+          if (sin->n_strx > strSize)
+            return true;
+          sout.name  = &strings[sin->n_strx];
+          sout.type  = (NListType)(sin->n_type & N_TYPE);
+          sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+          sout.sect  = sin->n_sect;
+          sout.desc  = sin->n_desc;
+          sout.value = sin->n_value;
+          if (sout.type == N_UNDF)
+            f->undefinedSymbols.push_back(sout);
+          else if (sout.scope == (SymbolScope)N_EXT)
+            f->globalSymbols.push_back(sout);
+          else if (sin->n_type & N_STAB)
+            f->stabsSymbols.push_back(sout);
+          else
+            f->localSymbols.push_back(sout);
+        }
+      }
+      }
+      break;
+    case LC_ID_DYLIB: {
+      const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
+      f->installName = lc + read32(&dl->dylib.name, isBig);
+      f->currentVersion = read32(&dl->dylib.current_version, isBig);
+      f->compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+      }
+      break;
+    case LC_DATA_IN_CODE: {
+      const linkedit_data_command *ldc =
+                            reinterpret_cast<const linkedit_data_command*>(lc);
+      dataInCode = reinterpret_cast<const data_in_code_entry *>(
+          start + read32(&ldc->dataoff, isBig));
+      dataInCodeSize = read32(&ldc->datasize, isBig);
+      }
+      break;
+    case LC_LOAD_DYLIB:
+    case LC_LOAD_WEAK_DYLIB:
+    case LC_REEXPORT_DYLIB:
+    case LC_LOAD_UPWARD_DYLIB: {
+      const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
+      DependentDylib entry;
+      entry.path = lc + read32(&dl->dylib.name, isBig);
+      entry.kind = LoadCommandType(cmd);
+      entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+      entry.currentVersion = read32(&dl->dylib.current_version, isBig);
+      f->dependentDylibs.push_back(entry);
+     }
+      break;
+    case LC_RPATH: {
+      const rpath_command *rpc = reinterpret_cast<const rpath_command *>(lc);
+      f->rpaths.push_back(lc + read32(&rpc->path, isBig));
+     }
+      break;
+    case LC_DYLD_INFO:
+    case LC_DYLD_INFO_ONLY:
+      dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
+      break;
+    case LC_VERSION_MIN_MACOSX:
+    case LC_VERSION_MIN_IPHONEOS:
+    case LC_VERSION_MIN_WATCHOS:
+    case LC_VERSION_MIN_TVOS:
+      // If we are emitting an object file, then we may take the load command
+      // kind from these commands and pass it on to the output
+      // file.
+      f->minOSVersionKind = (LoadCommandType)cmd;
+      break;
+    }
+    return false;
+  });
+  if (ec)
+    return std::move(ec);
+
+  if (dataInCode) {
+    // Convert on-disk data_in_code_entry array to DataInCode vector.
+    for (unsigned i=0; i < dataInCodeSize/sizeof(data_in_code_entry); ++i) {
+      DataInCode entry;
+      entry.offset = read32(&dataInCode[i].offset, isBig);
+      entry.length = read16(&dataInCode[i].length, isBig);
+      entry.kind =
+          (DataRegionType)read16((const uint8_t *)&dataInCode[i].kind, isBig);
+      f->dataInCode.push_back(entry);
+    }
+  }
+
+  if (dyldInfo) {
+    // If any exports, extract and add to normalized exportInfo vector.
+    if (dyldInfo->export_size) {
+      const uint8_t *trieStart = reinterpret_cast<const uint8_t *>(
+          start + read32(&dyldInfo->export_off, isBig));
+      ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig));
+      for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) {
+        Export normExport;
+        normExport.name = trieExport.name().copy(f->ownedAllocations);
+        normExport.offset = trieExport.address();
+        normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK);
+        normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK;
+        normExport.otherOffset = trieExport.other();
+        if (!trieExport.otherName().empty())
+          normExport.otherName = trieExport.otherName().copy(f->ownedAllocations);
+        f->exportInfo.push_back(normExport);
+      }
+    }
+  }
+
+  return std::move(f);
+}
+
+class MachOObjectReader : public Reader {
+public:
+  MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+    return (magic == file_magic::macho_object && mb.getBufferSize() > 32);
+  }
+
+  ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb,
+           const Registry &registry) const override {
+    std::unique_ptr<File> ret =
+      llvm::make_unique<MachOFile>(std::move(mb), &_ctx);
+    return std::move(ret);
+  }
+
+private:
+  MachOLinkingContext &_ctx;
+};
+
+class MachODylibReader : public Reader {
+public:
+  MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+    switch (magic) {
+    case file_magic::macho_dynamically_linked_shared_lib:
+    case file_magic::macho_dynamically_linked_shared_lib_stub:
+      return mb.getBufferSize() > 32;
+    default:
+      return false;
+    }
+  }
+
+  ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb,
+           const Registry &registry) const override {
+    std::unique_ptr<File> ret =
+        llvm::make_unique<MachODylibFile>(std::move(mb), &_ctx);
+    return std::move(ret);
+  }
+
+private:
+  MachOLinkingContext &_ctx;
+};
+
+} // namespace normalized
+} // namespace mach_o
+
+void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
+  MachOLinkingContext::Arch arch = ctx.arch();
+  add(std::unique_ptr<Reader>(new mach_o::normalized::MachOObjectReader(ctx)));
+  add(std::unique_ptr<Reader>(new mach_o::normalized::MachODylibReader(ctx)));
+  addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(),
+               ctx.archHandler().kindStrings());
+  add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+                           new mach_o::MachOYamlIOTaggedDocumentHandler(arch)));
+}
+
+
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
new file mode 100644 (file)
index 0000000..b38f705
--- /dev/null
@@ -0,0 +1,215 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+
+#include "MachONormalizedFile.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
+#include <system_error>
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+class ByteBuffer {
+public:
+  ByteBuffer() : _ostream(_bytes) { }
+
+  void append_byte(uint8_t b) {
+    _ostream << b;
+  }
+  void append_uleb128(uint64_t value) {
+    llvm::encodeULEB128(value, _ostream);
+  }
+  void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
+    unsigned min = llvm::getULEB128Size(value);
+    assert(min <= byteCount);
+    unsigned pad = byteCount - min;
+    llvm::encodeULEB128(value, _ostream, pad);
+  }
+  void append_sleb128(int64_t value) {
+    llvm::encodeSLEB128(value, _ostream);
+  }
+  void append_string(StringRef str) {
+    _ostream << str;
+    append_byte(0);
+  }
+  void align(unsigned alignment) {
+    while ( (_ostream.tell() % alignment) != 0 )
+      append_byte(0);
+  }
+  size_t size() {
+    return _ostream.tell();
+  }
+  const uint8_t *bytes() {
+    return reinterpret_cast<const uint8_t*>(_ostream.str().data());
+  }
+
+private:
+  SmallVector<char, 128>        _bytes;
+  // Stream ivar must be after SmallVector ivar to construct properly.
+  llvm::raw_svector_ostream     _ostream;
+};
+
+using namespace llvm::support::endian;
+using llvm::sys::getSwappedBytes;
+
+template<typename T>
+static inline uint16_t read16(const T *loc, bool isBig) {
+  assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
+  return isBig ? read16be(loc) : read16le(loc);
+}
+
+template<typename T>
+static inline uint32_t read32(const T *loc, bool isBig) {
+  assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
+  return isBig ? read32be(loc) : read32le(loc);
+}
+
+template<typename T>
+static inline uint64_t read64(const T *loc, bool isBig) {
+  assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
+  return isBig ? read64be(loc) : read64le(loc);
+}
+
+inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
+  if (isBig)
+    write16be(loc, value);
+  else
+    write16le(loc, value);
+}
+
+inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
+  if (isBig)
+    write32be(loc, value);
+  else
+    write32le(loc, value);
+}
+
+inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
+  if (isBig)
+    write64be(loc, value);
+  else
+    write64le(loc, value);
+}
+
+inline uint32_t
+bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
+                                                          uint8_t bitCount) {
+  const uint32_t mask = ((1<<bitCount)-1);
+  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+  return (value >> shift) & mask;
+}
+
+inline void
+bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
+                            uint8_t firstBit, uint8_t bitCount) {
+  const uint32_t mask = ((1<<bitCount)-1);
+  assert((newBits & mask) == newBits);
+  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+  bits &= ~(mask << shift);
+  bits |= (newBits << shift);
+}
+
+inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
+                                   bool isBigEndian) {
+  uint32_t r0 = read32(&r.r_word0, isBigEndian);
+  uint32_t r1 = read32(&r.r_word1, isBigEndian);
+
+  Relocation result;
+  if (r0 & llvm::MachO::R_SCATTERED) {
+    // scattered relocation record always laid out like big endian bit field
+    result.offset     = bitFieldExtract(r0, true, 8, 24);
+    result.scattered  = true;
+    result.type       = (RelocationInfoType)
+                        bitFieldExtract(r0, true, 4, 4);
+    result.length     = bitFieldExtract(r0, true, 2, 2);
+    result.pcRel      = bitFieldExtract(r0, true, 1, 1);
+    result.isExtern   = false;
+    result.value      = r1;
+    result.symbol     = 0;
+  } else {
+    result.offset     = r0;
+    result.scattered  = false;
+    result.type       = (RelocationInfoType)
+                        bitFieldExtract(r1, isBigEndian, 28, 4);
+    result.length     = bitFieldExtract(r1, isBigEndian, 25, 2);
+    result.pcRel      = bitFieldExtract(r1, isBigEndian, 24, 1);
+    result.isExtern   = bitFieldExtract(r1, isBigEndian, 27, 1);
+    result.value      = 0;
+    result.symbol     = bitFieldExtract(r1, isBigEndian, 0, 24);
+  }
+  return result;
+}
+
+
+inline llvm::MachO::any_relocation_info
+packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
+  uint32_t r0 = 0;
+  uint32_t r1 = 0;
+
+  if (r.scattered) {
+    r1 = r.value;
+    bitFieldSet(r0, true, r.offset,    8, 24);
+    bitFieldSet(r0, true, r.type,      4, 4);
+    bitFieldSet(r0, true, r.length,    2, 2);
+    bitFieldSet(r0, true, r.pcRel,     1, 1);
+    bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
+  } else {
+    r0 = r.offset;
+    bitFieldSet(r1, isBigEndian, r.type,     28, 4);
+    bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
+    bitFieldSet(r1, isBigEndian, r.length,   25, 2);
+    bitFieldSet(r1, isBigEndian, r.pcRel,    24, 1);
+    bitFieldSet(r1, isBigEndian, r.symbol,   0,  24);
+  }
+
+  llvm::MachO::any_relocation_info result;
+  result.r_word0 = swap ? getSwappedBytes(r0) : r0;
+  result.r_word1 = swap ? getSwappedBytes(r1) : r1;
+  return result;
+}
+
+inline StringRef getString16(const char s[16]) {
+  StringRef x = s;
+  if ( x.size() > 16 )
+    return x.substr(0, 16);
+  else
+    return x;
+}
+
+inline void setString16(StringRef str, char s[16]) {
+  memset(s, 0, 16);
+  memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
+}
+
+// Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
+// that the same table can be used to map mach-o sections to and from
+// DefinedAtom::ContentType.
+void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
+                                          StringRef &segmentName,
+                                          StringRef &sectionName,
+                                          SectionType &sectionType,
+                                          SectionAttr &sectionAttrs,
+                                          bool &relocsToDefinedCanBeImplicit);
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
new file mode 100644 (file)
index 0000000..bac41d2
--- /dev/null
@@ -0,0 +1,1551 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts normalized
+/// mach-o in memory to mach-o binary on disk.
+///
+///                 +---------------+
+///                 | binary mach-o |
+///                 +---------------+
+///                        ^
+///                        |
+///                        |
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <list>
+#include <map>
+#include <system_error>
+
+using namespace llvm::MachO;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode; // Forward declaration.
+
+struct TrieEdge : public llvm::ilist_node<TrieEdge> {
+  TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
+
+  StringRef          _subString;
+  struct TrieNode   *_child;
+};
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+
+namespace llvm {
+using lld::mach_o::normalized::TrieEdge;
+template <>
+struct ilist_alloc_traits<TrieEdge> : ilist_noalloc_traits<TrieEdge> {};
+} // namespace llvm
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode {
+  typedef llvm::ilist<TrieEdge> TrieEdgeList;
+
+  TrieNode(StringRef s)
+      : _cummulativeString(s), _address(0), _flags(0), _other(0),
+        _trieOffset(0), _hasExportInfo(false) {}
+  ~TrieNode() = default;
+
+  void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
+                 std::vector<TrieNode *> &allNodes);
+
+  void addOrderedNodes(const Export &entry,
+                       std::vector<TrieNode *> &allNodes);
+  bool updateOffset(uint32_t &offset);
+  void appendToByteBuffer(ByteBuffer &out);
+
+private:
+  StringRef                 _cummulativeString;
+  TrieEdgeList              _children;
+  uint64_t                  _address;
+  uint64_t                  _flags;
+  uint64_t                  _other;
+  StringRef                 _importedName;
+  uint32_t                  _trieOffset;
+  bool                      _hasExportInfo;
+  bool                      _ordered = false;
+};
+
+/// Utility class for writing a mach-o binary file given an in-memory
+/// normalized file.
+class MachOFileLayout {
+public:
+  /// All layout computation is done in the constructor.
+  MachOFileLayout(const NormalizedFile &file);
+
+  /// Returns the final file size as computed in the constructor.
+  size_t      size() const;
+
+  // Returns size of the mach_header and load commands.
+  size_t      headerAndLoadCommandsSize() const;
+
+  /// Writes the normalized file as a binary mach-o file to the specified
+  /// path.  This does not have a stream interface because the generated
+  /// file may need the 'x' bit set.
+  llvm::Error writeBinary(StringRef path);
+
+private:
+  uint32_t    loadCommandsSize(uint32_t &count);
+  void        buildFileOffsets();
+  void        writeMachHeader();
+  llvm::Error writeLoadCommands();
+  void        writeSectionContent();
+  void        writeRelocations();
+  void        writeSymbolTable();
+  void        writeRebaseInfo();
+  void        writeBindingInfo();
+  void        writeLazyBindingInfo();
+  void        writeExportInfo();
+  void        writeFunctionStartsInfo();
+  void        writeDataInCodeInfo();
+  void        writeLinkEditContent();
+  void        buildLinkEditInfo();
+  void        buildRebaseInfo();
+  void        buildBindInfo();
+  void        buildLazyBindInfo();
+  void        buildExportTrie();
+  void        computeFunctionStartsSize();
+  void        computeDataInCodeSize();
+  void        computeSymbolTableSizes();
+  void        buildSectionRelocations();
+  void        appendSymbols(const std::vector<Symbol> &symbols,
+                                      uint32_t &symOffset, uint32_t &strOffset);
+  uint32_t    indirectSymbolIndex(const Section &sect, uint32_t &index);
+  uint32_t    indirectSymbolElementSize(const Section &sect);
+
+  // For use as template parameter to load command methods.
+  struct MachO64Trait {
+    typedef llvm::MachO::segment_command_64 command;
+    typedef llvm::MachO::section_64         section;
+    enum { LC = llvm::MachO::LC_SEGMENT_64 };
+  };
+
+  // For use as template parameter to load command methods.
+  struct MachO32Trait {
+    typedef llvm::MachO::segment_command   command;
+    typedef llvm::MachO::section           section;
+    enum { LC = llvm::MachO::LC_SEGMENT };
+  };
+
+  template <typename T>
+  llvm::Error writeSingleSegmentLoadCommand(uint8_t *&lc);
+  template <typename T> llvm::Error writeSegmentLoadCommands(uint8_t *&lc);
+
+  uint32_t pointerAlign(uint32_t value);
+  static StringRef dyldPath();
+
+  struct SegExtraInfo {
+    uint32_t                    fileOffset;
+    uint32_t                    fileSize;
+    std::vector<const Section*> sections;
+  };
+  typedef std::map<const Segment*, SegExtraInfo> SegMap;
+  struct SectionExtraInfo {
+    uint32_t                    fileOffset;
+  };
+  typedef std::map<const Section*, SectionExtraInfo> SectionMap;
+
+  const NormalizedFile &_file;
+  std::error_code _ec;
+  uint8_t              *_buffer;
+  const bool            _is64;
+  const bool            _swap;
+  const bool            _bigEndianArch;
+  uint64_t              _seg1addr;
+  uint32_t              _startOfLoadCommands;
+  uint32_t              _countOfLoadCommands;
+  uint32_t              _endOfLoadCommands;
+  uint32_t              _startOfRelocations;
+  uint32_t              _startOfFunctionStarts;
+  uint32_t              _startOfDataInCode;
+  uint32_t              _startOfSymbols;
+  uint32_t              _startOfIndirectSymbols;
+  uint32_t              _startOfSymbolStrings;
+  uint32_t              _endOfSymbolStrings;
+  uint32_t              _symbolTableLocalsStartIndex;
+  uint32_t              _symbolTableGlobalsStartIndex;
+  uint32_t              _symbolTableUndefinesStartIndex;
+  uint32_t              _symbolStringPoolSize;
+  uint32_t              _symbolTableSize;
+  uint32_t              _functionStartsSize;
+  uint32_t              _dataInCodeSize;
+  uint32_t              _indirectSymbolTableCount;
+  // Used in object file creation only
+  uint32_t              _startOfSectionsContent;
+  uint32_t              _endOfSectionsContent;
+  // Used in final linked image only
+  uint32_t              _startOfLinkEdit;
+  uint32_t              _startOfRebaseInfo;
+  uint32_t              _endOfRebaseInfo;
+  uint32_t              _startOfBindingInfo;
+  uint32_t              _endOfBindingInfo;
+  uint32_t              _startOfLazyBindingInfo;
+  uint32_t              _endOfLazyBindingInfo;
+  uint32_t              _startOfExportTrie;
+  uint32_t              _endOfExportTrie;
+  uint32_t              _endOfLinkEdit;
+  uint64_t              _addressOfLinkEdit;
+  SegMap                _segInfo;
+  SectionMap            _sectInfo;
+  ByteBuffer            _rebaseInfo;
+  ByteBuffer            _bindingInfo;
+  ByteBuffer            _lazyBindingInfo;
+  ByteBuffer            _weakBindingInfo;
+  ByteBuffer            _exportTrie;
+};
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file) {
+  MachOFileLayout layout(file);
+  return layout.headerAndLoadCommandsSize();
+}
+
+StringRef MachOFileLayout::dyldPath() {
+  return "/usr/lib/dyld";
+}
+
+uint32_t MachOFileLayout::pointerAlign(uint32_t value) {
+  return llvm::alignTo(value, _is64 ? 8 : 4);
+}
+
+
+size_t MachOFileLayout::headerAndLoadCommandsSize() const {
+  return _endOfLoadCommands;
+}
+
+MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
+    : _file(file),
+      _is64(MachOLinkingContext::is64Bit(file.arch)),
+      _swap(!MachOLinkingContext::isHostEndian(file.arch)),
+      _bigEndianArch(MachOLinkingContext::isBigEndian(file.arch)),
+      _seg1addr(INT64_MAX) {
+  _startOfLoadCommands = _is64 ? sizeof(mach_header_64) : sizeof(mach_header);
+  const size_t segCommandBaseSize =
+          (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+  const size_t sectsSize = (_is64 ? sizeof(section_64) : sizeof(section));
+  if (file.fileType == llvm::MachO::MH_OBJECT) {
+    // object files have just one segment load command containing all sections
+    _endOfLoadCommands = _startOfLoadCommands
+                               + segCommandBaseSize
+                               + file.sections.size() * sectsSize
+                               + sizeof(symtab_command);
+    _countOfLoadCommands = 2;
+    if (file.hasMinVersionLoadCommand) {
+      _endOfLoadCommands += sizeof(version_min_command);
+      _countOfLoadCommands++;
+    }
+    if (!_file.functionStarts.empty()) {
+      _endOfLoadCommands += sizeof(linkedit_data_command);
+      _countOfLoadCommands++;
+    }
+    if (_file.generateDataInCodeLoadCommand) {
+      _endOfLoadCommands += sizeof(linkedit_data_command);
+      _countOfLoadCommands++;
+    }
+    // Assign file offsets to each section.
+    _startOfSectionsContent = _endOfLoadCommands;
+    unsigned relocCount = 0;
+    uint64_t offset = _startOfSectionsContent;
+    for (const Section &sect : file.sections) {
+      if (isZeroFillSection(sect.type))
+        _sectInfo[&sect].fileOffset = 0;
+      else {
+        offset = llvm::alignTo(offset, sect.alignment);
+        _sectInfo[&sect].fileOffset = offset;
+        offset += sect.content.size();
+      }
+      relocCount += sect.relocations.size();
+    }
+    _endOfSectionsContent = offset;
+
+    computeSymbolTableSizes();
+    computeFunctionStartsSize();
+    computeDataInCodeSize();
+
+    // Align start of relocations.
+    _startOfRelocations = pointerAlign(_endOfSectionsContent);
+    _startOfFunctionStarts = _startOfRelocations + relocCount * 8;
+    _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
+    _startOfSymbols = _startOfDataInCode + _dataInCodeSize;
+    // Add Indirect symbol table.
+    _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+    // Align start of symbol table and symbol strings.
+    _startOfSymbolStrings = _startOfIndirectSymbols
+                  + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+    _endOfSymbolStrings = _startOfSymbolStrings
+                          + pointerAlign(_symbolStringPoolSize);
+    _endOfLinkEdit = _endOfSymbolStrings;
+    DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "MachOFileLayout()\n"
+      << "  startOfLoadCommands=" << _startOfLoadCommands << "\n"
+      << "  countOfLoadCommands=" << _countOfLoadCommands << "\n"
+      << "  endOfLoadCommands=" << _endOfLoadCommands << "\n"
+      << "  startOfRelocations=" << _startOfRelocations << "\n"
+      << "  startOfSymbols=" << _startOfSymbols << "\n"
+      << "  startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+      << "  endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+      << "  startOfSectionsContent=" << _startOfSectionsContent << "\n"
+      << "  endOfSectionsContent=" << _endOfSectionsContent << "\n");
+  } else {
+    // Final linked images have one load command per segment.
+    _endOfLoadCommands = _startOfLoadCommands
+                          + loadCommandsSize(_countOfLoadCommands);
+
+    // Assign section file offsets.
+    buildFileOffsets();
+    buildLinkEditInfo();
+
+    // LINKEDIT of final linked images has in order:
+    // rebase info, binding info, lazy binding info, weak binding info,
+    // data-in-code, symbol table, indirect symbol table, symbol table strings.
+    _startOfRebaseInfo = _startOfLinkEdit;
+    _endOfRebaseInfo = _startOfRebaseInfo + _rebaseInfo.size();
+    _startOfBindingInfo = _endOfRebaseInfo;
+    _endOfBindingInfo = _startOfBindingInfo + _bindingInfo.size();
+    _startOfLazyBindingInfo = _endOfBindingInfo;
+    _endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
+    _startOfExportTrie = _endOfLazyBindingInfo;
+    _endOfExportTrie = _startOfExportTrie + _exportTrie.size();
+    _startOfFunctionStarts = _endOfExportTrie;
+    _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
+    _startOfSymbols = _startOfDataInCode + _dataInCodeSize;
+    _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+    _startOfSymbolStrings = _startOfIndirectSymbols
+                  + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+    _endOfSymbolStrings = _startOfSymbolStrings
+                          + pointerAlign(_symbolStringPoolSize);
+    _endOfLinkEdit = _endOfSymbolStrings;
+    DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "MachOFileLayout()\n"
+      << "  startOfLoadCommands=" << _startOfLoadCommands << "\n"
+      << "  countOfLoadCommands=" << _countOfLoadCommands << "\n"
+      << "  endOfLoadCommands=" << _endOfLoadCommands << "\n"
+      << "  startOfLinkEdit=" << _startOfLinkEdit << "\n"
+      << "  startOfRebaseInfo=" << _startOfRebaseInfo << "\n"
+      << "  endOfRebaseInfo=" << _endOfRebaseInfo << "\n"
+      << "  startOfBindingInfo=" << _startOfBindingInfo << "\n"
+      << "  endOfBindingInfo=" << _endOfBindingInfo << "\n"
+      << "  startOfLazyBindingInfo=" << _startOfLazyBindingInfo << "\n"
+      << "  endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
+      << "  startOfExportTrie=" << _startOfExportTrie << "\n"
+      << "  endOfExportTrie=" << _endOfExportTrie << "\n"
+      << "  startOfFunctionStarts=" << _startOfFunctionStarts << "\n"
+      << "  startOfDataInCode=" << _startOfDataInCode << "\n"
+      << "  startOfSymbols=" << _startOfSymbols << "\n"
+      << "  startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+      << "  endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+      << "  addressOfLinkEdit=" << _addressOfLinkEdit << "\n");
+  }
+}
+
+uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
+  uint32_t size = 0;
+  count = 0;
+
+  const size_t segCommandSize =
+          (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+  const size_t sectionSize = (_is64 ? sizeof(section_64) : sizeof(section));
+
+  // Add LC_SEGMENT for each segment.
+  size += _file.segments.size() * segCommandSize;
+  count += _file.segments.size();
+  // Add section record for each section.
+  size += _file.sections.size() * sectionSize;
+
+  // If creating a dylib, add LC_ID_DYLIB.
+  if (_file.fileType == llvm::MachO::MH_DYLIB) {
+    size += sizeof(dylib_command) + pointerAlign(_file.installName.size() + 1);
+    ++count;
+  }
+
+  // Add LC_DYLD_INFO
+  size += sizeof(dyld_info_command);
+  ++count;
+
+  // Add LC_SYMTAB
+  size += sizeof(symtab_command);
+  ++count;
+
+  // Add LC_DYSYMTAB
+  if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+    size += sizeof(dysymtab_command);
+    ++count;
+  }
+
+  // If main executable add LC_LOAD_DYLINKER
+  if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+    size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1);
+    ++count;
+  }
+
+  // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+  // LC_VERSION_MIN_TVOS
+  if (_file.hasMinVersionLoadCommand) {
+    size += sizeof(version_min_command);
+    ++count;
+  }
+
+  // Add LC_SOURCE_VERSION
+  size += sizeof(source_version_command);
+  ++count;
+
+  // If main executable add LC_MAIN
+  if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+    size += sizeof(entry_point_command);
+    ++count;
+  }
+
+  // Add LC_LOAD_DYLIB for each dependent dylib.
+  for (const DependentDylib &dep : _file.dependentDylibs) {
+    size += sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+    ++count;
+  }
+
+  // Add LC_RPATH
+  for (const StringRef &path : _file.rpaths) {
+    size += pointerAlign(sizeof(rpath_command) + path.size() + 1);
+    ++count;
+  }
+
+  // Add LC_FUNCTION_STARTS if needed
+  if (!_file.functionStarts.empty()) {
+    size += sizeof(linkedit_data_command);
+    ++count;
+  }
+
+  // Add LC_DATA_IN_CODE if requested.  Note, we do encode zero length entries.
+  // FIXME: Zero length entries is only to match ld64.  Should we change this?
+  if (_file.generateDataInCodeLoadCommand) {
+    size += sizeof(linkedit_data_command);
+    ++count;
+  }
+
+  return size;
+}
+
+static bool overlaps(const Segment &s1, const Segment &s2) {
+  if (s2.address >= s1.address+s1.size)
+    return false;
+  if (s1.address >= s2.address+s2.size)
+    return false;
+  return true;
+}
+
+static bool overlaps(const Section &s1, const Section &s2) {
+  if (s2.address >= s1.address+s1.content.size())
+    return false;
+  if (s1.address >= s2.address+s2.content.size())
+    return false;
+  return true;
+}
+
+void MachOFileLayout::buildFileOffsets() {
+  // Verify no segments overlap
+  for (const Segment &sg1 : _file.segments) {
+    for (const Segment &sg2 : _file.segments) {
+      if (&sg1 == &sg2)
+        continue;
+      if (overlaps(sg1,sg2)) {
+        _ec = make_error_code(llvm::errc::executable_format_error);
+        return;
+      }
+    }
+  }
+
+  // Verify no sections overlap
+  for (const Section &s1 : _file.sections) {
+    for (const Section &s2 : _file.sections) {
+      if (&s1 == &s2)
+        continue;
+      if (overlaps(s1,s2)) {
+        _ec = make_error_code(llvm::errc::executable_format_error);
+        return;
+      }
+    }
+  }
+
+  // Build side table of extra info about segments and sections.
+  SegExtraInfo t;
+  t.fileOffset = 0;
+  for (const Segment &sg : _file.segments) {
+    _segInfo[&sg] = t;
+  }
+  SectionExtraInfo t2;
+  t2.fileOffset = 0;
+  // Assign sections to segments.
+  for (const Section &s : _file.sections) {
+    _sectInfo[&s] = t2;
+    bool foundSegment = false;
+    for (const Segment &sg : _file.segments) {
+      if (sg.name.equals(s.segmentName)) {
+        if ((s.address >= sg.address)
+                        && (s.address+s.content.size() <= sg.address+sg.size)) {
+          _segInfo[&sg].sections.push_back(&s);
+          foundSegment = true;
+          break;
+        }
+      }
+    }
+    if (!foundSegment) {
+      _ec = make_error_code(llvm::errc::executable_format_error);
+      return;
+    }
+  }
+
+  // Assign file offsets.
+  uint32_t fileOffset = 0;
+  DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "buildFileOffsets()\n");
+  for (const Segment &sg : _file.segments) {
+    _segInfo[&sg].fileOffset = fileOffset;
+    if ((_seg1addr == INT64_MAX) && sg.init_access)
+      _seg1addr = sg.address;
+    DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "  segment=" << sg.name
+                  << ", fileOffset=" << _segInfo[&sg].fileOffset << "\n");
+
+    uint32_t segFileSize = 0;
+    // A segment that is not zero-fill must use a least one page of disk space.
+    if (sg.init_access)
+      segFileSize = _file.pageSize;
+    for (const Section *s : _segInfo[&sg].sections) {
+      uint32_t sectOffset = s->address - sg.address;
+      uint32_t sectFileSize =
+        isZeroFillSection(s->type) ? 0 : s->content.size();
+      segFileSize = std::max(segFileSize, sectOffset + sectFileSize);
+
+      _sectInfo[s].fileOffset = _segInfo[&sg].fileOffset + sectOffset;
+      DEBUG_WITH_TYPE("MachOFileLayout",
+                  llvm::dbgs() << "    section=" << s->sectionName
+                  << ", fileOffset=" << fileOffset << "\n");
+    }
+
+    // round up all segments to page aligned, except __LINKEDIT
+    if (!sg.name.equals("__LINKEDIT")) {
+      _segInfo[&sg].fileSize = llvm::alignTo(segFileSize, _file.pageSize);
+      fileOffset = llvm::alignTo(fileOffset + segFileSize, _file.pageSize);
+    }
+    _addressOfLinkEdit = sg.address + sg.size;
+  }
+  _startOfLinkEdit = fileOffset;
+}
+
+size_t MachOFileLayout::size() const {
+  return _endOfSymbolStrings;
+}
+
+void MachOFileLayout::writeMachHeader() {
+  auto cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+  // dynamic x86 executables on newer OS version should also set the
+  // CPU_SUBTYPE_LIB64 mask in the CPU subtype.
+  // FIXME: Check that this is a dynamic executable, not a static one.
+  if (_file.fileType == llvm::MachO::MH_EXECUTE &&
+      cpusubtype == CPU_SUBTYPE_X86_64_ALL &&
+      _file.os == MachOLinkingContext::OS::macOSX) {
+    uint32_t version;
+    bool failed = MachOLinkingContext::parsePackedVersion("10.5", version);
+    if (!failed && _file.minOSverson >= version)
+      cpusubtype |= CPU_SUBTYPE_LIB64;
+  }
+
+  mach_header *mh = reinterpret_cast<mach_header*>(_buffer);
+  mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC;
+  mh->cputype =  MachOLinkingContext::cpuTypeFromArch(_file.arch);
+  mh->cpusubtype = cpusubtype;
+  mh->filetype = _file.fileType;
+  mh->ncmds = _countOfLoadCommands;
+  mh->sizeofcmds = _endOfLoadCommands - _startOfLoadCommands;
+  mh->flags = _file.flags;
+  if (_swap)
+    swapStruct(*mh);
+}
+
+uint32_t MachOFileLayout::indirectSymbolIndex(const Section &sect,
+                                                   uint32_t &index) {
+  if (sect.indirectSymbols.empty())
+    return 0;
+  uint32_t result = index;
+  index += sect.indirectSymbols.size();
+  return result;
+}
+
+uint32_t MachOFileLayout::indirectSymbolElementSize(const Section &sect) {
+  if (sect.indirectSymbols.empty())
+    return 0;
+  if (sect.type != S_SYMBOL_STUBS)
+    return 0;
+  return sect.content.size() / sect.indirectSymbols.size();
+}
+
+template <typename T>
+llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
+  typename T::command* seg = reinterpret_cast<typename T::command*>(lc);
+  seg->cmd = T::LC;
+  seg->cmdsize = sizeof(typename T::command)
+                          + _file.sections.size() * sizeof(typename T::section);
+  uint8_t *next = lc + seg->cmdsize;
+  memset(seg->segname, 0, 16);
+  seg->vmaddr = 0;
+  seg->vmsize = _file.sections.back().address
+              + _file.sections.back().content.size();
+  seg->fileoff = _endOfLoadCommands;
+  seg->filesize = _sectInfo[&_file.sections.back()].fileOffset +
+                  _file.sections.back().content.size() -
+                  _sectInfo[&_file.sections.front()].fileOffset;
+  seg->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->nsects = _file.sections.size();
+  seg->flags = 0;
+  if (_swap)
+    swapStruct(*seg);
+  typename T::section *sout = reinterpret_cast<typename T::section*>
+                                              (lc+sizeof(typename T::command));
+  uint32_t relOffset = _startOfRelocations;
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Section &sin : _file.sections) {
+    setString16(sin.sectionName, sout->sectname);
+    setString16(sin.segmentName, sout->segname);
+    sout->addr = sin.address;
+    sout->size = sin.content.size();
+    sout->offset = _sectInfo[&sin].fileOffset;
+    sout->align = llvm::Log2_32(sin.alignment);
+    sout->reloff = sin.relocations.empty() ? 0 : relOffset;
+    sout->nreloc = sin.relocations.size();
+    sout->flags = sin.type | sin.attributes;
+    sout->reserved1 = indirectSymbolIndex(sin, indirectSymRunningIndex);
+    sout->reserved2 = indirectSymbolElementSize(sin);
+    relOffset += sin.relocations.size() * sizeof(any_relocation_info);
+    if (_swap)
+      swapStruct(*sout);
+    ++sout;
+  }
+  lc = next;
+  return llvm::Error::success();
+}
+
+template <typename T>
+llvm::Error MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Segment &seg : _file.segments) {
+    // Link edit has no sections and a custom range of address, so handle it
+    // specially.
+    SegExtraInfo &segInfo = _segInfo[&seg];
+    if (seg.name.equals("__LINKEDIT")) {
+      size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
+      typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+      cmd->cmd = T::LC;
+      cmd->cmdsize = sizeof(typename T::command);
+      uint8_t *next = lc + cmd->cmdsize;
+      setString16("__LINKEDIT", cmd->segname);
+      cmd->vmaddr   = _addressOfLinkEdit;
+      cmd->vmsize   = llvm::alignTo(linkeditSize, _file.pageSize);
+      cmd->fileoff  = _startOfLinkEdit;
+      cmd->filesize = linkeditSize;
+      cmd->initprot = seg.init_access;
+      cmd->maxprot  = seg.max_access;
+      cmd->nsects   = 0;
+      cmd->flags    = 0;
+      if (_swap)
+        swapStruct(*cmd);
+      lc = next;
+      continue;
+    }
+    // Write segment command with trailing sections.
+    typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+    cmd->cmd = T::LC;
+    cmd->cmdsize = sizeof(typename T::command)
+                        + segInfo.sections.size() * sizeof(typename T::section);
+    uint8_t *next = lc + cmd->cmdsize;
+    setString16(seg.name, cmd->segname);
+    cmd->vmaddr   = seg.address;
+    cmd->vmsize   = seg.size;
+    cmd->fileoff  = segInfo.fileOffset;
+    cmd->filesize = segInfo.fileSize;
+    cmd->initprot = seg.init_access;
+    cmd->maxprot  = seg.max_access;
+    cmd->nsects   = segInfo.sections.size();
+    cmd->flags    = 0;
+    if (_swap)
+      swapStruct(*cmd);
+    typename T::section *sect = reinterpret_cast<typename T::section*>
+                                               (lc+sizeof(typename T::command));
+    for (const Section *section : segInfo.sections) {
+      setString16(section->sectionName, sect->sectname);
+      setString16(section->segmentName, sect->segname);
+      sect->addr      = section->address;
+      sect->size      = section->content.size();
+      if (isZeroFillSection(section->type))
+        sect->offset  = 0;
+      else
+        sect->offset  = section->address - seg.address + segInfo.fileOffset;
+      sect->align     = llvm::Log2_32(section->alignment);
+      sect->reloff    = 0;
+      sect->nreloc    = 0;
+      sect->flags     = section->type | section->attributes;
+      sect->reserved1 = indirectSymbolIndex(*section, indirectSymRunningIndex);
+      sect->reserved2 = indirectSymbolElementSize(*section);
+      if (_swap)
+        swapStruct(*sect);
+      ++sect;
+    }
+    lc = reinterpret_cast<uint8_t*>(next);
+  }
+  return llvm::Error::success();
+}
+
+static void writeVersionMinLoadCommand(const NormalizedFile &_file,
+                                       bool _swap,
+                                       uint8_t *&lc) {
+  if (!_file.hasMinVersionLoadCommand)
+    return;
+  version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
+  switch (_file.os) {
+    case MachOLinkingContext::OS::unknown:
+      vm->cmd     = _file.minOSVersionKind;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = 0;
+      break;
+    case MachOLinkingContext::OS::macOSX:
+      vm->cmd     = LC_VERSION_MIN_MACOSX;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = _file.sdkVersion;
+      break;
+    case MachOLinkingContext::OS::iOS:
+    case MachOLinkingContext::OS::iOS_simulator:
+      vm->cmd     = LC_VERSION_MIN_IPHONEOS;
+      vm->cmdsize = sizeof(version_min_command);
+      vm->version = _file.minOSverson;
+      vm->sdk     = _file.sdkVersion;
+      break;
+  }
+  if (_swap)
+    swapStruct(*vm);
+  lc += sizeof(version_min_command);
+}
+
+llvm::Error MachOFileLayout::writeLoadCommands() {
+  uint8_t *lc = &_buffer[_startOfLoadCommands];
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    // Object files have one unnamed segment which holds all sections.
+    if (_is64) {
+     if (auto ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc))
+       return ec;
+    } else {
+      if (auto ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc))
+        return ec;
+    }
+    // Add LC_SYMTAB with symbol table info
+    symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+    st->cmd     = LC_SYMTAB;
+    st->cmdsize = sizeof(symtab_command);
+    st->symoff  = _startOfSymbols;
+    st->nsyms   = _file.stabsSymbols.size() + _file.localSymbols.size() +
+                  _file.globalSymbols.size() + _file.undefinedSymbols.size();
+    st->stroff  = _startOfSymbolStrings;
+    st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+    if (_swap)
+      swapStruct(*st);
+    lc += sizeof(symtab_command);
+
+    // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+    // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS
+    writeVersionMinLoadCommand(_file, _swap, lc);
+
+    // Add LC_FUNCTION_STARTS if needed.
+    if (_functionStartsSize != 0) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_FUNCTION_STARTS;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfFunctionStarts;
+      dl->datasize = _functionStartsSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+
+    // Add LC_DATA_IN_CODE if requested.
+    if (_file.generateDataInCodeLoadCommand) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_DATA_IN_CODE;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfDataInCode;
+      dl->datasize = _dataInCodeSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+  } else {
+    // Final linked images have sections under segments.
+    if (_is64) {
+      if (auto ec = writeSegmentLoadCommands<MachO64Trait>(lc))
+        return ec;
+    } else {
+      if (auto ec = writeSegmentLoadCommands<MachO32Trait>(lc))
+        return ec;
+    }
+
+    // Add LC_ID_DYLIB command for dynamic libraries.
+    if (_file.fileType == llvm::MachO::MH_DYLIB) {
+      dylib_command *dc = reinterpret_cast<dylib_command*>(lc);
+      StringRef path = _file.installName;
+      uint32_t size = sizeof(dylib_command) + pointerAlign(path.size() + 1);
+      dc->cmd                         = LC_ID_DYLIB;
+      dc->cmdsize                     = size;
+      dc->dylib.name                  = sizeof(dylib_command); // offset
+      // needs to be some constant value different than the one in LC_LOAD_DYLIB
+      dc->dylib.timestamp             = 1;
+      dc->dylib.current_version       = _file.currentVersion;
+      dc->dylib.compatibility_version = _file.compatVersion;
+      if (_swap)
+        swapStruct(*dc);
+      memcpy(lc + sizeof(dylib_command), path.begin(), path.size());
+      lc[sizeof(dylib_command) + path.size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_DYLD_INFO_ONLY.
+    dyld_info_command* di = reinterpret_cast<dyld_info_command*>(lc);
+    di->cmd            = LC_DYLD_INFO_ONLY;
+    di->cmdsize        = sizeof(dyld_info_command);
+    di->rebase_off     = _rebaseInfo.size() ? _startOfRebaseInfo : 0;
+    di->rebase_size    = _rebaseInfo.size();
+    di->bind_off       = _bindingInfo.size() ? _startOfBindingInfo : 0;
+    di->bind_size      = _bindingInfo.size();
+    di->weak_bind_off  = 0;
+    di->weak_bind_size = 0;
+    di->lazy_bind_off  = _lazyBindingInfo.size() ? _startOfLazyBindingInfo : 0;
+    di->lazy_bind_size = _lazyBindingInfo.size();
+    di->export_off     = _exportTrie.size() ? _startOfExportTrie : 0;
+    di->export_size    = _exportTrie.size();
+    if (_swap)
+      swapStruct(*di);
+    lc += sizeof(dyld_info_command);
+
+    // Add LC_SYMTAB with symbol table info.
+    symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+    st->cmd     = LC_SYMTAB;
+    st->cmdsize = sizeof(symtab_command);
+    st->symoff  = _startOfSymbols;
+    st->nsyms   = _file.stabsSymbols.size() + _file.localSymbols.size() +
+                  _file.globalSymbols.size() + _file.undefinedSymbols.size();
+    st->stroff  = _startOfSymbolStrings;
+    st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+    if (_swap)
+      swapStruct(*st);
+    lc += sizeof(symtab_command);
+
+    // Add LC_DYSYMTAB
+    if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+      dysymtab_command* dst = reinterpret_cast<dysymtab_command*>(lc);
+      dst->cmd            = LC_DYSYMTAB;
+      dst->cmdsize        = sizeof(dysymtab_command);
+      dst->ilocalsym      = _symbolTableLocalsStartIndex;
+      dst->nlocalsym      = _file.stabsSymbols.size() +
+                            _file.localSymbols.size();
+      dst->iextdefsym     = _symbolTableGlobalsStartIndex;
+      dst->nextdefsym     = _file.globalSymbols.size();
+      dst->iundefsym      = _symbolTableUndefinesStartIndex;
+      dst->nundefsym      = _file.undefinedSymbols.size();
+      dst->tocoff         = 0;
+      dst->ntoc           = 0;
+      dst->modtaboff      = 0;
+      dst->nmodtab        = 0;
+      dst->extrefsymoff   = 0;
+      dst->nextrefsyms    = 0;
+      dst->indirectsymoff = _startOfIndirectSymbols;
+      dst->nindirectsyms  = _indirectSymbolTableCount;
+      dst->extreloff      = 0;
+      dst->nextrel        = 0;
+      dst->locreloff      = 0;
+      dst->nlocrel        = 0;
+      if (_swap)
+        swapStruct(*dst);
+      lc += sizeof(dysymtab_command);
+    }
+
+    // If main executable, add LC_LOAD_DYLINKER
+    if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+      // Build LC_LOAD_DYLINKER load command.
+      uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1);
+      dylinker_command* dl = reinterpret_cast<dylinker_command*>(lc);
+      dl->cmd              = LC_LOAD_DYLINKER;
+      dl->cmdsize          = size;
+      dl->name             = sizeof(dylinker_command); // offset
+      if (_swap)
+        swapStruct(*dl);
+      memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size());
+      lc[sizeof(dylinker_command)+dyldPath().size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+    // LC_VERSION_MIN_TVOS
+    writeVersionMinLoadCommand(_file, _swap, lc);
+
+    // Add LC_SOURCE_VERSION
+    {
+      // Note, using a temporary here to appease UB as we may not be aligned
+      // enough for a struct containing a uint64_t when emitting a 32-bit binary
+      source_version_command sv;
+      sv.cmd       = LC_SOURCE_VERSION;
+      sv.cmdsize   = sizeof(source_version_command);
+      sv.version   = _file.sourceVersion;
+      if (_swap)
+        swapStruct(sv);
+      memcpy(lc, &sv, sizeof(source_version_command));
+      lc += sizeof(source_version_command);
+    }
+
+    // If main executable, add LC_MAIN.
+    if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+      // Build LC_MAIN load command.
+      // Note, using a temporary here to appease UB as we may not be aligned
+      // enough for a struct containing a uint64_t when emitting a 32-bit binary
+      entry_point_command ep;
+      ep.cmd       = LC_MAIN;
+      ep.cmdsize   = sizeof(entry_point_command);
+      ep.entryoff  = _file.entryAddress - _seg1addr;
+      ep.stacksize = _file.stackSize;
+      if (_swap)
+        swapStruct(ep);
+      memcpy(lc, &ep, sizeof(entry_point_command));
+      lc += sizeof(entry_point_command);
+    }
+
+    // Add LC_LOAD_DYLIB commands
+    for (const DependentDylib &dep : _file.dependentDylibs) {
+      dylib_command* dc = reinterpret_cast<dylib_command*>(lc);
+      uint32_t size = sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+      dc->cmd                         = dep.kind;
+      dc->cmdsize                     = size;
+      dc->dylib.name                  = sizeof(dylib_command); // offset
+      // needs to be some constant value different than the one in LC_ID_DYLIB
+      dc->dylib.timestamp             = 2;
+      dc->dylib.current_version       = dep.currentVersion;
+      dc->dylib.compatibility_version = dep.compatVersion;
+      if (_swap)
+        swapStruct(*dc);
+      memcpy(lc+sizeof(dylib_command), dep.path.begin(), dep.path.size());
+      lc[sizeof(dylib_command)+dep.path.size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_RPATH
+    for (const StringRef &path : _file.rpaths) {
+      rpath_command *rpc = reinterpret_cast<rpath_command *>(lc);
+      uint32_t size = pointerAlign(sizeof(rpath_command) + path.size() + 1);
+      rpc->cmd                         = LC_RPATH;
+      rpc->cmdsize                     = size;
+      rpc->path                        = sizeof(rpath_command); // offset
+      if (_swap)
+        swapStruct(*rpc);
+      memcpy(lc+sizeof(rpath_command), path.begin(), path.size());
+      lc[sizeof(rpath_command)+path.size()] = '\0';
+      lc += size;
+    }
+
+    // Add LC_FUNCTION_STARTS if needed.
+    if (_functionStartsSize != 0) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_FUNCTION_STARTS;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfFunctionStarts;
+      dl->datasize = _functionStartsSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+
+    // Add LC_DATA_IN_CODE if requested.
+    if (_file.generateDataInCodeLoadCommand) {
+      linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+      dl->cmd      = LC_DATA_IN_CODE;
+      dl->cmdsize  = sizeof(linkedit_data_command);
+      dl->dataoff  = _startOfDataInCode;
+      dl->datasize = _dataInCodeSize;
+      if (_swap)
+        swapStruct(*dl);
+      lc += sizeof(linkedit_data_command);
+    }
+  }
+  return llvm::Error::success();
+}
+
+void MachOFileLayout::writeSectionContent() {
+  for (const Section &s : _file.sections) {
+    // Copy all section content to output buffer.
+    if (isZeroFillSection(s.type))
+      continue;
+    if (s.content.empty())
+      continue;
+    uint32_t offset = _sectInfo[&s].fileOffset;
+    uint8_t *p = &_buffer[offset];
+    memcpy(p, &s.content[0], s.content.size());
+    p += s.content.size();
+  }
+}
+
+void MachOFileLayout::writeRelocations() {
+  uint32_t relOffset = _startOfRelocations;
+  for (Section sect : _file.sections) {
+    for (Relocation r : sect.relocations) {
+      any_relocation_info* rb = reinterpret_cast<any_relocation_info*>(
+                                                           &_buffer[relOffset]);
+      *rb = packRelocation(r, _swap, _bigEndianArch);
+      relOffset += sizeof(any_relocation_info);
+    }
+  }
+}
+
+void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols,
+                                   uint32_t &symOffset, uint32_t &strOffset) {
+  for (const Symbol &sym : symbols) {
+    if (_is64) {
+      nlist_64* nb = reinterpret_cast<nlist_64*>(&_buffer[symOffset]);
+      nb->n_strx = strOffset - _startOfSymbolStrings;
+      nb->n_type = sym.type | sym.scope;
+      nb->n_sect = sym.sect;
+      nb->n_desc = sym.desc;
+      nb->n_value = sym.value;
+      if (_swap)
+        swapStruct(*nb);
+      symOffset += sizeof(nlist_64);
+    } else {
+      nlist* nb = reinterpret_cast<nlist*>(&_buffer[symOffset]);
+      nb->n_strx = strOffset - _startOfSymbolStrings;
+      nb->n_type = sym.type | sym.scope;
+      nb->n_sect = sym.sect;
+      nb->n_desc = sym.desc;
+      nb->n_value = sym.value;
+      if (_swap)
+        swapStruct(*nb);
+      symOffset += sizeof(nlist);
+    }
+    memcpy(&_buffer[strOffset], sym.name.begin(), sym.name.size());
+    strOffset += sym.name.size();
+    _buffer[strOffset++] ='\0'; // Strings in table have nul terminator.
+  }
+}
+
+void MachOFileLayout::writeFunctionStartsInfo() {
+  if (!_functionStartsSize)
+    return;
+  memcpy(&_buffer[_startOfFunctionStarts], _file.functionStarts.data(),
+         _functionStartsSize);
+}
+
+void MachOFileLayout::writeDataInCodeInfo() {
+  uint32_t offset = _startOfDataInCode;
+  for (const DataInCode &entry : _file.dataInCode) {
+    data_in_code_entry *dst = reinterpret_cast<data_in_code_entry*>(
+                                                             &_buffer[offset]);
+    dst->offset = entry.offset;
+    dst->length = entry.length;
+    dst->kind   = entry.kind;
+    if (_swap)
+      swapStruct(*dst);
+    offset += sizeof(data_in_code_entry);
+  }
+}
+
+void MachOFileLayout::writeSymbolTable() {
+  // Write symbol table and symbol strings in parallel.
+  uint32_t symOffset = _startOfSymbols;
+  uint32_t strOffset = _startOfSymbolStrings;
+  // Reserve n_strx offset of zero to mean no name.
+  _buffer[strOffset++] = ' ';
+  _buffer[strOffset++] = '\0';
+  appendSymbols(_file.stabsSymbols, symOffset, strOffset);
+  appendSymbols(_file.localSymbols, symOffset, strOffset);
+  appendSymbols(_file.globalSymbols, symOffset, strOffset);
+  appendSymbols(_file.undefinedSymbols, symOffset, strOffset);
+  // Write indirect symbol table array.
+  uint32_t *indirects = reinterpret_cast<uint32_t*>
+                                            (&_buffer[_startOfIndirectSymbols]);
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    // Object files have sections in same order as input normalized file.
+    for (const Section &section : _file.sections) {
+      for (uint32_t index : section.indirectSymbols) {
+        if (_swap)
+          *indirects++ = llvm::sys::getSwappedBytes(index);
+        else
+          *indirects++ = index;
+      }
+    }
+  } else {
+    // Final linked images must sort sections from normalized file.
+    for (const Segment &seg : _file.segments) {
+      SegExtraInfo &segInfo = _segInfo[&seg];
+      for (const Section *section : segInfo.sections) {
+        for (uint32_t index : section->indirectSymbols) {
+          if (_swap)
+            *indirects++ = llvm::sys::getSwappedBytes(index);
+          else
+            *indirects++ = index;
+        }
+      }
+    }
+  }
+}
+
+void MachOFileLayout::writeRebaseInfo() {
+  memcpy(&_buffer[_startOfRebaseInfo], _rebaseInfo.bytes(), _rebaseInfo.size());
+}
+
+void MachOFileLayout::writeBindingInfo() {
+  memcpy(&_buffer[_startOfBindingInfo],
+                                    _bindingInfo.bytes(), _bindingInfo.size());
+}
+
+void MachOFileLayout::writeLazyBindingInfo() {
+  memcpy(&_buffer[_startOfLazyBindingInfo],
+                            _lazyBindingInfo.bytes(), _lazyBindingInfo.size());
+}
+
+void MachOFileLayout::writeExportInfo() {
+  memcpy(&_buffer[_startOfExportTrie], _exportTrie.bytes(), _exportTrie.size());
+}
+
+void MachOFileLayout::buildLinkEditInfo() {
+  buildRebaseInfo();
+  buildBindInfo();
+  buildLazyBindInfo();
+  buildExportTrie();
+  computeSymbolTableSizes();
+  computeFunctionStartsSize();
+  computeDataInCodeSize();
+}
+
+void MachOFileLayout::buildSectionRelocations() {
+
+}
+
+void MachOFileLayout::buildRebaseInfo() {
+  // TODO: compress rebasing info.
+  for (const RebaseLocation& entry : _file.rebasingInfo) {
+    _rebaseInfo.append_byte(REBASE_OPCODE_SET_TYPE_IMM | entry.kind);
+    _rebaseInfo.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+                            | entry.segIndex);
+    _rebaseInfo.append_uleb128(entry.segOffset);
+    _rebaseInfo.append_uleb128(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1);
+  }
+  _rebaseInfo.append_byte(REBASE_OPCODE_DONE);
+  _rebaseInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildBindInfo() {
+  // TODO: compress bind info.
+  uint64_t lastAddend = 0;
+  int lastOrdinal = 0x80000000;
+  StringRef lastSymbolName;
+  BindType lastType = (BindType)0;
+  Hex32 lastSegOffset = ~0U;
+  uint8_t lastSegIndex = (uint8_t)~0U;
+  for (const BindLocation& entry : _file.bindingInfo) {
+    if (entry.ordinal != lastOrdinal) {
+      if (entry.ordinal <= 0)
+        _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+                                 (entry.ordinal & BIND_IMMEDIATE_MASK));
+      else if (entry.ordinal <= BIND_IMMEDIATE_MASK)
+        _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+                                 entry.ordinal);
+      else {
+        _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+        _bindingInfo.append_uleb128(entry.ordinal);
+      }
+      lastOrdinal = entry.ordinal;
+    }
+
+    if (lastSymbolName != entry.symbolName) {
+      _bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+      _bindingInfo.append_string(entry.symbolName);
+      lastSymbolName = entry.symbolName;
+    }
+
+    if (lastType != entry.kind) {
+      _bindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind);
+      lastType = entry.kind;
+    }
+
+    if (lastSegIndex != entry.segIndex || lastSegOffset != entry.segOffset) {
+      _bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+                               | entry.segIndex);
+      _bindingInfo.append_uleb128(entry.segOffset);
+      lastSegIndex = entry.segIndex;
+      lastSegOffset = entry.segOffset;
+    }
+    if (entry.addend != lastAddend) {
+      _bindingInfo.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+      _bindingInfo.append_sleb128(entry.addend);
+      lastAddend = entry.addend;
+    }
+    _bindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+  }
+  _bindingInfo.append_byte(BIND_OPCODE_DONE);
+  _bindingInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildLazyBindInfo() {
+  for (const BindLocation& entry : _file.lazyBindingInfo) {
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+                            | entry.segIndex);
+    _lazyBindingInfo.append_uleb128(entry.segOffset);
+    if (entry.ordinal <= 0)
+      _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+                                   (entry.ordinal & BIND_IMMEDIATE_MASK));
+    else if (entry.ordinal <= BIND_IMMEDIATE_MASK)
+      _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+                                   entry.ordinal);
+    else {
+      _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+      _lazyBindingInfo.append_uleb128(entry.ordinal);
+    }
+    // FIXME: We need to | the opcode here with flags.
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+    _lazyBindingInfo.append_string(entry.symbolName);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_DONE);
+  }
+  _lazyBindingInfo.align(_is64 ? 8 : 4);
+}
+
+void TrieNode::addSymbol(const Export& entry,
+                         BumpPtrAllocator &allocator,
+                         std::vector<TrieNode*> &allNodes) {
+  StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
+  for (TrieEdge &edge : _children) {
+    StringRef edgeStr = edge._subString;
+    if (partialStr.startswith(edgeStr)) {
+      // Already have matching edge, go down that path.
+      edge._child->addSymbol(entry, allocator, allNodes);
+      return;
+    }
+    // See if string has commmon prefix with existing edge.
+    for (int n=edgeStr.size()-1; n > 0; --n) {
+      if (partialStr.substr(0, n).equals(edgeStr.substr(0, n))) {
+        // Splice in new node:  was A -> C,  now A -> B -> C
+        StringRef bNodeStr = edge._child->_cummulativeString;
+        bNodeStr = bNodeStr.drop_back(edgeStr.size()-n).copy(allocator);
+        auto *bNode = new (allocator) TrieNode(bNodeStr);
+        allNodes.push_back(bNode);
+        TrieNode* cNode = edge._child;
+        StringRef abEdgeStr = edgeStr.substr(0,n).copy(allocator);
+        StringRef bcEdgeStr = edgeStr.substr(n).copy(allocator);
+        DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+                        << "splice in TrieNode('" << bNodeStr
+                        << "') between edge '"
+                        << abEdgeStr << "' and edge='"
+                        << bcEdgeStr<< "'\n");
+        TrieEdge& abEdge = edge;
+        abEdge._subString = abEdgeStr;
+        abEdge._child = bNode;
+        auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
+        bNode->_children.insert(bNode->_children.end(), bcEdge);
+        bNode->addSymbol(entry, allocator, allNodes);
+        return;
+      }
+    }
+  }
+  if (entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+    assert(entry.otherOffset != 0);
+  }
+  if (entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
+    assert(entry.otherOffset != 0);
+  }
+  // No commonality with any existing child, make a new edge.
+  auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator));
+  auto *newEdge = new (allocator) TrieEdge(partialStr, newNode);
+  _children.insert(_children.end(), newEdge);
+  DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+                   << "new TrieNode('" << entry.name << "') with edge '"
+                   << partialStr << "' from node='"
+                   << _cummulativeString << "'\n");
+  newNode->_address = entry.offset;
+  newNode->_flags = entry.flags | entry.kind;
+  newNode->_other = entry.otherOffset;
+  if ((entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && !entry.otherName.empty())
+    newNode->_importedName = entry.otherName.copy(allocator);
+  newNode->_hasExportInfo = true;
+  allNodes.push_back(newNode);
+}
+
+void TrieNode::addOrderedNodes(const Export& entry,
+                               std::vector<TrieNode*> &orderedNodes) {
+  if (!_ordered) {
+    orderedNodes.push_back(this);
+    _ordered = true;
+  }
+
+  StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
+  for (TrieEdge &edge : _children) {
+    StringRef edgeStr = edge._subString;
+    if (partialStr.startswith(edgeStr)) {
+      // Already have matching edge, go down that path.
+      edge._child->addOrderedNodes(entry, orderedNodes);
+      return;
+    }
+  }
+}
+
+bool TrieNode::updateOffset(uint32_t& offset) {
+  uint32_t nodeSize = 1; // Length when no export info
+  if (_hasExportInfo) {
+    if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+      nodeSize = llvm::getULEB128Size(_flags);
+      nodeSize += llvm::getULEB128Size(_other); // Other contains ordinal.
+      nodeSize += _importedName.size();
+      ++nodeSize; // Trailing zero in imported name.
+    } else {
+      nodeSize = llvm::getULEB128Size(_flags) + llvm::getULEB128Size(_address);
+      if (_flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+        nodeSize += llvm::getULEB128Size(_other);
+    }
+    // Overall node size so far is uleb128 of export info + actual export info.
+    nodeSize += llvm::getULEB128Size(nodeSize);
+  }
+  // Compute size of all child edges.
+  ++nodeSize; // Byte for number of chidren.
+  for (TrieEdge &edge : _children) {
+    nodeSize += edge._subString.size() + 1 // String length.
+              + llvm::getULEB128Size(edge._child->_trieOffset); // Offset len.
+  }
+  // On input, 'offset' is new prefered location for this node.
+  bool result = (_trieOffset != offset);
+  // Store new location in node object for use by parents.
+  _trieOffset = offset;
+  // Update offset for next iteration.
+  offset += nodeSize;
+  // Return true if _trieOffset was changed.
+  return result;
+}
+
+void TrieNode::appendToByteBuffer(ByteBuffer &out) {
+  if (_hasExportInfo) {
+    if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+      if (!_importedName.empty()) {
+        // nodes with re-export info: size, flags, ordinal, import-name
+        uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                          + llvm::getULEB128Size(_other)
+                          + _importedName.size() + 1;
+        assert(nodeSize < 256);
+        out.append_byte(nodeSize);
+        out.append_uleb128(_flags);
+        out.append_uleb128(_other);
+        out.append_string(_importedName);
+      } else {
+        // nodes without re-export info: size, flags, ordinal, empty-string
+        uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                          + llvm::getULEB128Size(_other) + 1;
+        assert(nodeSize < 256);
+        out.append_byte(nodeSize);
+        out.append_uleb128(_flags);
+        out.append_uleb128(_other);
+        out.append_byte(0);
+      }
+    } else if ( _flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+      // Nodes with export info: size, flags, address, other
+      uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                        + llvm::getULEB128Size(_address)
+                        + llvm::getULEB128Size(_other);
+      assert(nodeSize < 256);
+      out.append_byte(nodeSize);
+      out.append_uleb128(_flags);
+      out.append_uleb128(_address);
+      out.append_uleb128(_other);
+    } else {
+      // Nodes with export info: size, flags, address
+      uint32_t nodeSize = llvm::getULEB128Size(_flags)
+                        + llvm::getULEB128Size(_address);
+      assert(nodeSize < 256);
+      out.append_byte(nodeSize);
+      out.append_uleb128(_flags);
+      out.append_uleb128(_address);
+    }
+  } else {
+    // Node with no export info.
+    uint32_t nodeSize = 0;
+    out.append_byte(nodeSize);
+  }
+  // Add number of children.
+  assert(_children.size() < 256);
+  out.append_byte(_children.size());
+  // Append each child edge substring and node offset.
+  for (TrieEdge &edge : _children) {
+    out.append_string(edge._subString);
+    out.append_uleb128(edge._child->_trieOffset);
+  }
+}
+
+void MachOFileLayout::buildExportTrie() {
+  if (_file.exportInfo.empty())
+    return;
+
+  // For all temporary strings and objects used building trie.
+  BumpPtrAllocator allocator;
+
+  // Build trie of all exported symbols.
+  auto *rootNode = new (allocator) TrieNode(StringRef());
+  std::vector<TrieNode*> allNodes;
+  allNodes.reserve(_file.exportInfo.size()*2);
+  allNodes.push_back(rootNode);
+  for (const Export& entry : _file.exportInfo) {
+    rootNode->addSymbol(entry, allocator, allNodes);
+  }
+
+  std::vector<TrieNode*> orderedNodes;
+  orderedNodes.reserve(allNodes.size());
+
+  for (const Export& entry : _file.exportInfo)
+    rootNode->addOrderedNodes(entry, orderedNodes);
+
+  // Assign each node in the vector an offset in the trie stream, iterating
+  // until all uleb128 sizes have stabilized.
+  bool more;
+  do {
+    uint32_t offset = 0;
+    more = false;
+    for (TrieNode* node : orderedNodes) {
+      if (node->updateOffset(offset))
+        more = true;
+    }
+  } while (more);
+
+  // Serialize trie to ByteBuffer.
+  for (TrieNode* node : orderedNodes) {
+    node->appendToByteBuffer(_exportTrie);
+  }
+  _exportTrie.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::computeSymbolTableSizes() {
+  // MachO symbol tables have three ranges: locals, globals, and undefines
+  const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist));
+  _symbolTableSize = nlistSize * (_file.stabsSymbols.size()
+                                + _file.localSymbols.size()
+                                + _file.globalSymbols.size()
+                                + _file.undefinedSymbols.size());
+  // Always reserve 1-byte for the empty string and 1-byte for its terminator.
+  _symbolStringPoolSize = 2;
+  for (const Symbol &sym : _file.stabsSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  for (const Symbol &sym : _file.localSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  for (const Symbol &sym : _file.globalSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  for (const Symbol &sym : _file.undefinedSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  _symbolTableLocalsStartIndex = 0;
+  _symbolTableGlobalsStartIndex = _file.stabsSymbols.size() +
+                                  _file.localSymbols.size();
+  _symbolTableUndefinesStartIndex = _symbolTableGlobalsStartIndex
+                                    + _file.globalSymbols.size();
+
+  _indirectSymbolTableCount = 0;
+  for (const Section &sect : _file.sections) {
+    _indirectSymbolTableCount += sect.indirectSymbols.size();
+  }
+}
+
+void MachOFileLayout::computeFunctionStartsSize() {
+  _functionStartsSize = _file.functionStarts.size();
+}
+
+void MachOFileLayout::computeDataInCodeSize() {
+  _dataInCodeSize = _file.dataInCode.size() * sizeof(data_in_code_entry);
+}
+
+void MachOFileLayout::writeLinkEditContent() {
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    writeRelocations();
+    writeFunctionStartsInfo();
+    writeDataInCodeInfo();
+    writeSymbolTable();
+  } else {
+    writeRebaseInfo();
+    writeBindingInfo();
+    writeLazyBindingInfo();
+    // TODO: add weak binding info
+    writeExportInfo();
+    writeFunctionStartsInfo();
+    writeDataInCodeInfo();
+    writeSymbolTable();
+  }
+}
+
+llvm::Error MachOFileLayout::writeBinary(StringRef path) {
+  // Check for pending error from constructor.
+  if (_ec)
+    return llvm::errorCodeToError(_ec);
+  // Create FileOutputBuffer with calculated size.
+  unsigned flags = 0;
+  if (_file.fileType != llvm::MachO::MH_OBJECT)
+    flags = llvm::FileOutputBuffer::F_executable;
+  ErrorOr<std::unique_ptr<llvm::FileOutputBuffer>> fobOrErr =
+      llvm::FileOutputBuffer::create(path, size(), flags);
+  if (std::error_code ec = fobOrErr.getError())
+    return llvm::errorCodeToError(ec);
+  std::unique_ptr<llvm::FileOutputBuffer> &fob = *fobOrErr;
+  // Write content.
+  _buffer = fob->getBufferStart();
+  writeMachHeader();
+  if (auto ec = writeLoadCommands())
+    return ec;
+  writeSectionContent();
+  writeLinkEditContent();
+  fob->commit();
+
+  return llvm::Error::success();
+}
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path) {
+  MachOFileLayout layout(file);
+  return layout.writeBinary(path);
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
new file mode 100644 (file)
index 0000000..e58e3d2
--- /dev/null
@@ -0,0 +1,1600 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file Converts from in-memory Atoms to in-memory normalized mach-o.
+///
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+///                        ^
+///                        |
+///                        |
+///                    +-------+
+///                    | Atoms |
+///                    +-------+
+
+#include "ArchHandler.h"
+#include "DebugInfo.h"
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include <map>
+#include <system_error>
+#include <unordered_set>
+
+using llvm::StringRef;
+using llvm::isa;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+using namespace lld;
+
+namespace {
+
+struct AtomInfo {
+  const DefinedAtom  *atom;
+  uint64_t            offsetInSection;
+};
+
+struct SectionInfo {
+  SectionInfo(StringRef seg, StringRef sect, SectionType type,
+              const MachOLinkingContext &ctxt, uint32_t attr,
+              bool relocsToDefinedCanBeImplicit);
+
+  StringRef                 segmentName;
+  StringRef                 sectionName;
+  SectionType               type;
+  uint32_t                  attributes;
+  uint64_t                  address;
+  uint64_t                  size;
+  uint16_t                  alignment;
+
+  /// If this is set, the any relocs in this section which point to defined
+  /// addresses can be implicitly generated.  This is the case for the
+  /// __eh_frame section where references to the function can be implicit if the
+  /// function is defined.
+  bool                      relocsToDefinedCanBeImplicit;
+
+
+  std::vector<AtomInfo>     atomsAndOffsets;
+  uint32_t                  normalizedSectionIndex;
+  uint32_t                  finalSectionIndex;
+};
+
+SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t,
+                         const MachOLinkingContext &ctxt, uint32_t attrs,
+                         bool relocsToDefinedCanBeImplicit)
+ : segmentName(sg), sectionName(sct), type(t), attributes(attrs),
+                 address(0), size(0), alignment(1),
+                 relocsToDefinedCanBeImplicit(relocsToDefinedCanBeImplicit),
+                 normalizedSectionIndex(0), finalSectionIndex(0) {
+  uint16_t align = 1;
+  if (ctxt.sectionAligned(segmentName, sectionName, align)) {
+    alignment = align;
+  }
+}
+
+struct SegmentInfo {
+  SegmentInfo(StringRef name);
+
+  StringRef                  name;
+  uint64_t                   address;
+  uint64_t                   size;
+  uint32_t                   init_access;
+  uint32_t                   max_access;
+  std::vector<SectionInfo*>  sections;
+  uint32_t                   normalizedSegmentIndex;
+};
+
+SegmentInfo::SegmentInfo(StringRef n)
+ : name(n), address(0), size(0), init_access(0), max_access(0),
+   normalizedSegmentIndex(0) {
+}
+
+class Util {
+public:
+  Util(const MachOLinkingContext &ctxt)
+      : _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr),
+        _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {}
+  ~Util();
+
+  void      processDefinedAtoms(const lld::File &atomFile);
+  void      processAtomAttributes(const DefinedAtom *atom);
+  void      assignAtomToSection(const DefinedAtom *atom);
+  void      organizeSections();
+  void      assignAddressesToSections(const NormalizedFile &file);
+  uint32_t  fileFlags();
+  void      copySegmentInfo(NormalizedFile &file);
+  void      copySectionInfo(NormalizedFile &file);
+  void      updateSectionInfo(NormalizedFile &file);
+  void      buildAtomToAddressMap();
+  llvm::Error synthesizeDebugNotes(NormalizedFile &file);
+  llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file);
+  void      addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
+  void      addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
+  void      addExportInfo(const lld::File &, NormalizedFile &file);
+  void      addSectionRelocs(const lld::File &, NormalizedFile &file);
+  void      addFunctionStarts(const lld::File &, NormalizedFile &file);
+  void      buildDataInCodeArray(const lld::File &, NormalizedFile &file);
+  void      addDependentDylibs(const lld::File &, NormalizedFile &file);
+  void      copyEntryPointAddress(NormalizedFile &file);
+  void      copySectionContent(NormalizedFile &file);
+
+  bool allSourceFilesHaveMinVersions() const {
+    return _allSourceFilesHaveMinVersions;
+  }
+
+  uint32_t minVersion() const {
+    return _minVersion;
+  }
+
+  LoadCommandType minVersionCommandType() const {
+    return _minVersionCommandType;
+  }
+
+private:
+  typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
+  typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
+
+  struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; };
+  typedef llvm::StringMap<DylibInfo> DylibPathToInfo;
+
+  SectionInfo *sectionForAtom(const DefinedAtom*);
+  SectionInfo *getRelocatableSection(DefinedAtom::ContentType type);
+  SectionInfo *getFinalSection(DefinedAtom::ContentType type);
+  void         appendAtom(SectionInfo *sect, const DefinedAtom *atom);
+  SegmentInfo *segmentForName(StringRef segName);
+  void         layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
+  void         layoutSectionsInTextSegment(size_t, SegmentInfo *, uint64_t &);
+  void         copySectionContent(SectionInfo *si, ContentBytes &content);
+  uint16_t     descBits(const DefinedAtom* atom);
+  int          dylibOrdinal(const SharedLibraryAtom *sa);
+  void         segIndexForSection(const SectionInfo *sect,
+                             uint8_t &segmentIndex, uint64_t &segmentStartAddr);
+  const Atom  *targetOfLazyPointer(const DefinedAtom *lpAtom);
+  const Atom  *targetOfStub(const DefinedAtom *stubAtom);
+  llvm::Error getSymbolTableRegion(const DefinedAtom* atom,
+                                   bool &inGlobalsRegion,
+                                   SymbolScope &symbolScope);
+  void         appendSection(SectionInfo *si, NormalizedFile &file);
+  uint32_t     sectionIndexForAtom(const Atom *atom);
+
+  typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
+  struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
+  struct AtomSorter {
+    bool operator()(const AtomAndIndex &left, const AtomAndIndex &right);
+  };
+  struct SegmentSorter {
+    bool operator()(const SegmentInfo *left, const SegmentInfo *right);
+    static unsigned weight(const SegmentInfo *);
+  };
+  struct TextSectionSorter {
+    bool operator()(const SectionInfo *left, const SectionInfo *right);
+    static unsigned weight(const SectionInfo *);
+  };
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler          &_archHandler;
+  llvm::BumpPtrAllocator        _allocator;
+  std::vector<SectionInfo*>     _sectionInfos;
+  std::vector<SegmentInfo*>     _segmentInfos;
+  TypeToSection                 _sectionMap;
+  std::vector<SectionInfo*>     _customSections;
+  AtomToAddress                 _atomToAddress;
+  DylibPathToInfo               _dylibInfo;
+  const DefinedAtom            *_entryAtom;
+  AtomToIndex                   _atomToSymbolIndex;
+  std::vector<const Atom *>     _machHeaderAliasAtoms;
+  bool                          _hasTLVDescriptors;
+  bool                          _subsectionsViaSymbols;
+  bool                          _allSourceFilesHaveMinVersions = true;
+  LoadCommandType               _minVersionCommandType = (LoadCommandType)0;
+  uint32_t                      _minVersion = 0;
+  std::vector<lld::mach_o::Stab> _stabs;
+};
+
+Util::~Util() {
+  // The SectionInfo structs are BumpPtr allocated, but atomsAndOffsets needs
+  // to be deleted.
+  for (SectionInfo *si : _sectionInfos) {
+    // clear() destroys vector elements, but does not deallocate.
+    // Instead use swap() to deallocate vector buffer.
+    std::vector<AtomInfo> empty;
+    si->atomsAndOffsets.swap(empty);
+  }
+  // The SegmentInfo structs are BumpPtr allocated, but sections needs
+  // to be deleted.
+  for (SegmentInfo *sgi : _segmentInfos) {
+    std::vector<SectionInfo*> empty2;
+    sgi->sections.swap(empty2);
+  }
+}
+
+SectionInfo *Util::getRelocatableSection(DefinedAtom::ContentType type) {
+  StringRef segmentName;
+  StringRef sectionName;
+  SectionType sectionType;
+  SectionAttr sectionAttrs;
+  bool relocsToDefinedCanBeImplicit;
+
+  // Use same table used by when parsing .o files.
+  relocatableSectionInfoForContentType(type, segmentName, sectionName,
+                                       sectionType, sectionAttrs,
+                                       relocsToDefinedCanBeImplicit);
+  // If we already have a SectionInfo with this name, re-use it.
+  // This can happen if two ContentType map to the same mach-o section.
+  for (auto sect : _sectionMap) {
+    if (sect.second->sectionName.equals(sectionName) &&
+        sect.second->segmentName.equals(segmentName)) {
+      return sect.second;
+    }
+  }
+  // Otherwise allocate new SectionInfo object.
+  auto *sect = new (_allocator)
+      SectionInfo(segmentName, sectionName, sectionType, _ctx, sectionAttrs,
+                  relocsToDefinedCanBeImplicit);
+  _sectionInfos.push_back(sect);
+  _sectionMap[type] = sect;
+  return sect;
+}
+
+#define ENTRY(seg, sect, type, atomType) \
+  {seg, sect, type, DefinedAtom::atomType }
+
+struct MachOFinalSectionFromAtomType {
+  StringRef                 segmentName;
+  StringRef                 sectionName;
+  SectionType               sectionType;
+  DefinedAtom::ContentType  atomType;
+};
+
+const MachOFinalSectionFromAtomType sectsToAtomType[] = {
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeCode),
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeMachHeader),
+  ENTRY("__TEXT", "__cstring",        S_CSTRING_LITERALS, typeCString),
+  ENTRY("__TEXT", "__ustring",        S_REGULAR,          typeUTF16String),
+  ENTRY("__TEXT", "__const",          S_REGULAR,          typeConstant),
+  ENTRY("__TEXT", "__const",          S_4BYTE_LITERALS,   typeLiteral4),
+  ENTRY("__TEXT", "__const",          S_8BYTE_LITERALS,   typeLiteral8),
+  ENTRY("__TEXT", "__const",          S_16BYTE_LITERALS,  typeLiteral16),
+  ENTRY("__TEXT", "__stubs",          S_SYMBOL_STUBS,     typeStub),
+  ENTRY("__TEXT", "__stub_helper",    S_REGULAR,          typeStubHelper),
+  ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR,          typeLSDA),
+  ENTRY("__TEXT", "__eh_frame",       S_COALESCED,        typeCFI),
+  ENTRY("__TEXT", "__unwind_info",    S_REGULAR,          typeProcessedUnwindInfo),
+  ENTRY("__DATA", "__data",           S_REGULAR,          typeData),
+  ENTRY("__DATA", "__const",          S_REGULAR,          typeConstData),
+  ENTRY("__DATA", "__cfstring",       S_REGULAR,          typeCFString),
+  ENTRY("__DATA", "__la_symbol_ptr",  S_LAZY_SYMBOL_POINTERS,
+                                                          typeLazyPointer),
+  ENTRY("__DATA", "__mod_init_func",  S_MOD_INIT_FUNC_POINTERS,
+                                                          typeInitializerPtr),
+  ENTRY("__DATA", "__mod_term_func",  S_MOD_TERM_FUNC_POINTERS,
+                                                          typeTerminatorPtr),
+  ENTRY("__DATA", "__got",            S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeGOT),
+  ENTRY("__DATA", "__nl_symbol_ptr",  S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeNonLazyPointer),
+  ENTRY("__DATA", "__thread_vars",    S_THREAD_LOCAL_VARIABLES,
+                                                          typeThunkTLV),
+  ENTRY("__DATA", "__thread_data",    S_THREAD_LOCAL_REGULAR,
+                                                          typeTLVInitialData),
+  ENTRY("__DATA", "__thread_ptrs",    S_THREAD_LOCAL_VARIABLE_POINTERS,
+                                                          typeTLVInitializerPtr),
+  ENTRY("__DATA", "__thread_bss",     S_THREAD_LOCAL_ZEROFILL,
+                                                         typeTLVInitialZeroFill),
+  ENTRY("__DATA", "__bss",            S_ZEROFILL,         typeZeroFill),
+  ENTRY("__DATA", "__interposing",    S_INTERPOSING,      typeInterposingTuples),
+};
+#undef ENTRY
+
+SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
+  for (auto &p : sectsToAtomType) {
+    if (p.atomType != atomType)
+      continue;
+    SectionAttr sectionAttrs = 0;
+    switch (atomType) {
+    case DefinedAtom::typeMachHeader:
+    case DefinedAtom::typeCode:
+    case DefinedAtom::typeStub:
+    case DefinedAtom::typeStubHelper:
+      sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
+      break;
+    case DefinedAtom::typeThunkTLV:
+      _hasTLVDescriptors = true;
+      break;
+    default:
+      break;
+    }
+    // If we already have a SectionInfo with this name, re-use it.
+    // This can happen if two ContentType map to the same mach-o section.
+    for (auto sect : _sectionMap) {
+      if (sect.second->sectionName.equals(p.sectionName) &&
+          sect.second->segmentName.equals(p.segmentName)) {
+        return sect.second;
+      }
+    }
+    // Otherwise allocate new SectionInfo object.
+    auto *sect = new (_allocator) SectionInfo(
+        p.segmentName, p.sectionName, p.sectionType, _ctx, sectionAttrs,
+        /* relocsToDefinedCanBeImplicit */ false);
+    _sectionInfos.push_back(sect);
+    _sectionMap[atomType] = sect;
+    return sect;
+  }
+  llvm_unreachable("content type not yet supported");
+}
+
+SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
+  if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
+    // Section for this atom is derived from content type.
+    DefinedAtom::ContentType type = atom->contentType();
+    auto pos = _sectionMap.find(type);
+    if ( pos != _sectionMap.end() )
+      return pos->second;
+    bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+    return rMode ? getRelocatableSection(type) : getFinalSection(type);
+  } else {
+    // This atom needs to be in a custom section.
+    StringRef customName = atom->customSectionName();
+    // Look to see if we have already allocated the needed custom section.
+    for(SectionInfo *sect : _customSections) {
+      const DefinedAtom *firstAtom = sect->atomsAndOffsets.front().atom;
+      if (firstAtom->customSectionName().equals(customName)) {
+        return sect;
+      }
+    }
+    // Not found, so need to create a new custom section.
+    size_t seperatorIndex = customName.find('/');
+    assert(seperatorIndex != StringRef::npos);
+    StringRef segName = customName.slice(0, seperatorIndex);
+    StringRef sectName = customName.drop_front(seperatorIndex + 1);
+    auto *sect =
+        new (_allocator) SectionInfo(segName, sectName, S_REGULAR, _ctx,
+                                     0, /* relocsToDefinedCanBeImplicit */ false);
+    _customSections.push_back(sect);
+    _sectionInfos.push_back(sect);
+    return sect;
+  }
+}
+
+void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
+  // Figure out offset for atom in this section given alignment constraints.
+  uint64_t offset = sect->size;
+  DefinedAtom::Alignment atomAlign = atom->alignment();
+  uint64_t align = atomAlign.value;
+  uint64_t requiredModulus = atomAlign.modulus;
+  uint64_t currentModulus = (offset % align);
+  if ( currentModulus != requiredModulus ) {
+    if ( requiredModulus > currentModulus )
+      offset += requiredModulus-currentModulus;
+    else
+      offset += align+requiredModulus-currentModulus;
+  }
+  // Record max alignment of any atom in this section.
+  if (align > sect->alignment)
+    sect->alignment = atomAlign.value;
+  // Assign atom to this section with this offset.
+  AtomInfo ai = {atom, offset};
+  sect->atomsAndOffsets.push_back(ai);
+  // Update section size to include this atom.
+  sect->size = offset + atom->size();
+}
+
+void Util::processDefinedAtoms(const lld::File &atomFile) {
+  for (const DefinedAtom *atom : atomFile.defined()) {
+    processAtomAttributes(atom);
+    assignAtomToSection(atom);
+  }
+}
+
+void Util::processAtomAttributes(const DefinedAtom *atom) {
+  if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) {
+    // If the file doesn't use subsections via symbols, then make sure we don't
+    // add that flag to the final output file if we have a relocatable file.
+    if (!machoFile->subsectionsViaSymbols())
+      _subsectionsViaSymbols = false;
+
+    // All the source files must have min versions for us to output an object
+    // file with a min version.
+    if (auto v = machoFile->minVersion())
+      _minVersion = std::max(_minVersion, v);
+    else
+      _allSourceFilesHaveMinVersions = false;
+
+    // If we don't have a platform load command, but one of the source files
+    // does, then take the one from the file.
+    if (!_minVersionCommandType)
+      if (auto v = machoFile->minVersionLoadCommandKind())
+        _minVersionCommandType = v;
+  }
+}
+
+void Util::assignAtomToSection(const DefinedAtom *atom) {
+  if (atom->contentType() == DefinedAtom::typeMachHeader) {
+    _machHeaderAliasAtoms.push_back(atom);
+    // Assign atom to this section with this offset.
+    AtomInfo ai = {atom, 0};
+    sectionForAtom(atom)->atomsAndOffsets.push_back(ai);
+  } else if (atom->contentType() == DefinedAtom::typeDSOHandle)
+    _machHeaderAliasAtoms.push_back(atom);
+  else
+    appendAtom(sectionForAtom(atom), atom);
+}
+
+SegmentInfo *Util::segmentForName(StringRef segName) {
+  for (SegmentInfo *si : _segmentInfos) {
+    if ( si->name.equals(segName) )
+      return si;
+  }
+  auto *info = new (_allocator) SegmentInfo(segName);
+
+  // Set the initial segment protection.
+  if (segName.equals("__TEXT"))
+    info->init_access = VM_PROT_READ | VM_PROT_EXECUTE;
+  else if (segName.equals("__PAGEZERO"))
+    info->init_access = 0;
+  else if (segName.equals("__LINKEDIT"))
+    info->init_access = VM_PROT_READ;
+  else {
+    // All others default to read-write
+    info->init_access = VM_PROT_READ | VM_PROT_WRITE;
+  }
+
+  // Set max segment protection
+  // Note, its overkill to use a switch statement here, but makes it so much
+  // easier to use switch coverage to catch new cases.
+  switch (_ctx.os()) {
+    case lld::MachOLinkingContext::OS::unknown:
+    case lld::MachOLinkingContext::OS::macOSX:
+    case lld::MachOLinkingContext::OS::iOS_simulator:
+      if (segName.equals("__PAGEZERO")) {
+        info->max_access = 0;
+        break;
+      }
+      // All others default to all
+      info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+      break;
+    case lld::MachOLinkingContext::OS::iOS:
+      // iPhoneOS always uses same protection for max and initial
+      info->max_access = info->init_access;
+      break;
+  }
+  _segmentInfos.push_back(info);
+  return info;
+}
+
+unsigned Util::SegmentSorter::weight(const SegmentInfo *seg) {
+ return llvm::StringSwitch<unsigned>(seg->name)
+    .Case("__PAGEZERO",  1)
+    .Case("__TEXT",      2)
+    .Case("__DATA",      3)
+    .Default(100);
+}
+
+bool Util::SegmentSorter::operator()(const SegmentInfo *left,
+                                  const SegmentInfo *right) {
+  return (weight(left) < weight(right));
+}
+
+unsigned Util::TextSectionSorter::weight(const SectionInfo *sect) {
+ return llvm::StringSwitch<unsigned>(sect->sectionName)
+    .Case("__text",         1)
+    .Case("__stubs",        2)
+    .Case("__stub_helper",  3)
+    .Case("__const",        4)
+    .Case("__cstring",      5)
+    .Case("__unwind_info",  98)
+    .Case("__eh_frame",     99)
+    .Default(10);
+}
+
+bool Util::TextSectionSorter::operator()(const SectionInfo *left,
+                                         const SectionInfo *right) {
+  return (weight(left) < weight(right));
+}
+
+void Util::organizeSections() {
+  // NOTE!: Keep this in sync with assignAddressesToSections.
+  switch (_ctx.outputMachOType()) {
+    case llvm::MachO::MH_EXECUTE:
+      // Main executables, need a zero-page segment
+      segmentForName("__PAGEZERO");
+      // Fall into next case.
+      LLVM_FALLTHROUGH;
+    case llvm::MachO::MH_DYLIB:
+    case llvm::MachO::MH_BUNDLE:
+      // All dynamic code needs TEXT segment to hold the load commands.
+      segmentForName("__TEXT");
+      break;
+    default:
+      break;
+  }
+  segmentForName("__LINKEDIT");
+
+  // Group sections into segments.
+  for (SectionInfo *si : _sectionInfos) {
+    SegmentInfo *seg = segmentForName(si->segmentName);
+    seg->sections.push_back(si);
+  }
+  // Sort segments.
+  std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
+
+  // Sort sections within segments.
+  for (SegmentInfo *seg : _segmentInfos) {
+    if (seg->name.equals("__TEXT")) {
+      std::sort(seg->sections.begin(), seg->sections.end(),
+                TextSectionSorter());
+    }
+  }
+
+  // Record final section indexes.
+  uint32_t segmentIndex = 0;
+  uint32_t sectionIndex = 1;
+  for (SegmentInfo *seg : _segmentInfos) {
+    seg->normalizedSegmentIndex = segmentIndex++;
+    for (SectionInfo *sect : seg->sections)
+      sect->finalSectionIndex = sectionIndex++;
+  }
+}
+
+void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
+  seg->address = addr;
+  for (SectionInfo *sect : seg->sections) {
+    sect->address = llvm::alignTo(addr, sect->alignment);
+    addr = sect->address + sect->size;
+  }
+  seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
+}
+
+// __TEXT segment lays out backwards so padding is at front after load commands.
+void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
+                                                               uint64_t &addr) {
+  seg->address = addr;
+  // Walks sections starting at end to calculate padding for start.
+  int64_t taddr = 0;
+  for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) {
+    SectionInfo *sect = *it;
+    taddr -= sect->size;
+    taddr = taddr & (0 - sect->alignment);
+  }
+  int64_t padding = taddr - hlcSize;
+  while (padding < 0)
+    padding += _ctx.pageSize();
+  // Start assigning section address starting at padded offset.
+  addr += (padding + hlcSize);
+  for (SectionInfo *sect : seg->sections) {
+    sect->address = llvm::alignTo(addr, sect->alignment);
+    addr = sect->address + sect->size;
+  }
+  seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
+}
+
+void Util::assignAddressesToSections(const NormalizedFile &file) {
+  // NOTE!: Keep this in sync with organizeSections.
+  size_t hlcSize = headerAndLoadCommandsSize(file);
+  uint64_t address = 0;
+  for (SegmentInfo *seg : _segmentInfos) {
+    if (seg->name.equals("__PAGEZERO")) {
+      seg->size = _ctx.pageZeroSize();
+      address += seg->size;
+    }
+    else if (seg->name.equals("__TEXT")) {
+      // _ctx.baseAddress()  == 0 implies it was either unspecified or
+      // pageZeroSize is also 0. In either case resetting address is safe.
+      address = _ctx.baseAddress() ? _ctx.baseAddress() : address;
+      layoutSectionsInTextSegment(hlcSize, seg, address);
+    } else
+      layoutSectionsInSegment(seg, address);
+
+    address = llvm::alignTo(address, _ctx.pageSize());
+  }
+  DEBUG_WITH_TYPE("WriterMachO-norm",
+    llvm::dbgs() << "assignAddressesToSections()\n";
+    for (SegmentInfo *sgi : _segmentInfos) {
+      llvm::dbgs()  << "   address=" << llvm::format("0x%08llX", sgi->address)
+                    << ", size="  << llvm::format("0x%08llX", sgi->size)
+                    << ", segment-name='" << sgi->name
+                    << "'\n";
+      for (SectionInfo *si : sgi->sections) {
+        llvm::dbgs()<< "      addr="  << llvm::format("0x%08llX", si->address)
+                    << ", size="  << llvm::format("0x%08llX", si->size)
+                    << ", section-name='" << si->sectionName
+                    << "\n";
+      }
+    }
+  );
+}
+
+void Util::copySegmentInfo(NormalizedFile &file) {
+  for (SegmentInfo *sgi : _segmentInfos) {
+    Segment seg;
+    seg.name    = sgi->name;
+    seg.address = sgi->address;
+    seg.size    = sgi->size;
+    seg.init_access  = sgi->init_access;
+    seg.max_access  = sgi->max_access;
+    file.segments.push_back(seg);
+  }
+}
+
+void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
+   // Add new empty section to end of file.sections.
+  Section temp;
+  file.sections.push_back(std::move(temp));
+  Section* normSect = &file.sections.back();
+  // Copy fields to normalized section.
+  normSect->segmentName   = si->segmentName;
+  normSect->sectionName   = si->sectionName;
+  normSect->type          = si->type;
+  normSect->attributes    = si->attributes;
+  normSect->address       = si->address;
+  normSect->alignment     = si->alignment;
+  // Record where normalized section is.
+  si->normalizedSectionIndex = file.sections.size()-1;
+}
+
+void Util::copySectionContent(NormalizedFile &file) {
+  const bool r = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+
+  // Utility function for ArchHandler to find address of atom in output file.
+  auto addrForAtom = [&] (const Atom &atom) -> uint64_t {
+    auto pos = _atomToAddress.find(&atom);
+    assert(pos != _atomToAddress.end());
+    return pos->second;
+  };
+
+  auto sectionAddrForAtom = [&] (const Atom &atom) -> uint64_t {
+    for (const SectionInfo *sectInfo : _sectionInfos)
+      for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets)
+        if (atomInfo.atom == &atom)
+          return sectInfo->address;
+    llvm_unreachable("atom not assigned to section");
+  };
+
+  for (SectionInfo *si : _sectionInfos) {
+    Section *normSect = &file.sections[si->normalizedSectionIndex];
+    if (isZeroFillSection(si->type)) {
+      const uint8_t *empty = nullptr;
+      normSect->content = llvm::makeArrayRef(empty, si->size);
+      continue;
+    }
+    // Copy content from atoms to content buffer for section.
+    llvm::MutableArrayRef<uint8_t> sectionContent;
+    if (si->size) {
+      uint8_t *sectContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
+      sectionContent = llvm::MutableArrayRef<uint8_t>(sectContent, si->size);
+      normSect->content = sectionContent;
+    }
+    for (AtomInfo &ai : si->atomsAndOffsets) {
+      if (!ai.atom->size()) {
+        assert(ai.atom->begin() == ai.atom->end() &&
+               "Cannot have references without content");
+        continue;
+      }
+      auto atomContent = sectionContent.slice(ai.offsetInSection,
+                                              ai.atom->size());
+      _archHandler.generateAtomContent(*ai.atom, r, addrForAtom,
+                                       sectionAddrForAtom, _ctx.baseAddress(),
+                                       atomContent);
+    }
+  }
+}
+
+void Util::copySectionInfo(NormalizedFile &file) {
+  file.sections.reserve(_sectionInfos.size());
+  // Write sections grouped by segment.
+  for (SegmentInfo *sgi : _segmentInfos) {
+    for (SectionInfo *si : sgi->sections) {
+      appendSection(si, file);
+    }
+  }
+}
+
+void Util::updateSectionInfo(NormalizedFile &file) {
+  file.sections.reserve(_sectionInfos.size());
+  // sections grouped by segment.
+  for (SegmentInfo *sgi : _segmentInfos) {
+    Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex];
+    normSeg->address = sgi->address;
+    normSeg->size = sgi->size;
+    for (SectionInfo *si : sgi->sections) {
+      Section *normSect = &file.sections[si->normalizedSectionIndex];
+      normSect->address = si->address;
+    }
+  }
+}
+
+void Util::copyEntryPointAddress(NormalizedFile &nFile) {
+  if (!_entryAtom) {
+    nFile.entryAddress = 0;
+    return;
+  }
+
+  if (_ctx.outputTypeHasEntry()) {
+    if (_archHandler.isThumbFunction(*_entryAtom))
+      nFile.entryAddress = (_atomToAddress[_entryAtom] | 1);
+    else
+      nFile.entryAddress = _atomToAddress[_entryAtom];
+  }
+}
+
+void Util::buildAtomToAddressMap() {
+  DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                   << "assign atom addresses:\n");
+  const bool lookForEntry = _ctx.outputTypeHasEntry();
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      _atomToAddress[info.atom] = sect->address + info.offsetInSection;
+      if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
+          (info.atom->size() != 0) &&
+          info.atom->name() == _ctx.entrySymbolName()) {
+        _entryAtom = info.atom;
+      }
+      DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                      << "   address="
+                      << llvm::format("0x%016X", _atomToAddress[info.atom])
+                      << llvm::format("    0x%09lX", info.atom)
+                      << ", file=#"
+                      << info.atom->file().ordinal()
+                      << ", atom=#"
+                      << info.atom->ordinal()
+                      << ", name="
+                      << info.atom->name()
+                      << ", type="
+                      << info.atom->contentType()
+                      << "\n");
+    }
+  }
+  DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                  << "assign header alias atom addresses:\n");
+  for (const Atom *atom : _machHeaderAliasAtoms) {
+    _atomToAddress[atom] = _ctx.baseAddress();
+#ifndef NDEBUG
+    if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) {
+      DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                      << "   address="
+                      << llvm::format("0x%016X", _atomToAddress[atom])
+                      << llvm::format("    0x%09lX", atom)
+                      << ", file=#"
+                      << definedAtom->file().ordinal()
+                      << ", atom=#"
+                      << definedAtom->ordinal()
+                      << ", name="
+                      << definedAtom->name()
+                      << ", type="
+                      << definedAtom->contentType()
+                      << "\n");
+    } else {
+      DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                      << "   address="
+                      << llvm::format("0x%016X", _atomToAddress[atom])
+                      << " atom=" << atom
+                      << " name=" << atom->name() << "\n");
+    }
+#endif
+  }
+}
+
+llvm::Error Util::synthesizeDebugNotes(NormalizedFile &file) {
+
+  // Bail out early if we don't need to generate a debug map.
+  if (_ctx.debugInfoMode() == MachOLinkingContext::DebugInfoMode::noDebugMap)
+    return llvm::Error::success();
+
+  std::vector<const DefinedAtom*> atomsNeedingDebugNotes;
+  std::set<const mach_o::MachOFile*> filesWithStabs;
+  bool objFileHasDwarf = false;
+  const File *objFile = nullptr;
+
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      if (const DefinedAtom *atom = dyn_cast<DefinedAtom>(info.atom)) {
+
+        // FIXME: No stabs/debug-notes for symbols that wouldn't be in the
+        //        symbol table.
+        // FIXME: No stabs/debug-notes for kernel dtrace probes.
+
+        if (atom->contentType() == DefinedAtom::typeCFI ||
+            atom->contentType() == DefinedAtom::typeCString)
+          continue;
+
+        // Whenever we encounter a new file, update the 'objfileHasDwarf' flag.
+        if (&info.atom->file() != objFile) {
+          objFileHasDwarf = false;
+          if (const mach_o::MachOFile *atomFile =
+              dyn_cast<mach_o::MachOFile>(&info.atom->file())) {
+            if (atomFile->debugInfo()) {
+              if (isa<mach_o::DwarfDebugInfo>(atomFile->debugInfo()))
+                objFileHasDwarf = true;
+              else if (isa<mach_o::StabsDebugInfo>(atomFile->debugInfo()))
+                filesWithStabs.insert(atomFile);
+            }
+          }
+        }
+
+        // If this atom is from a file that needs dwarf, add it to the list.
+        if (objFileHasDwarf)
+          atomsNeedingDebugNotes.push_back(info.atom);
+      }
+    }
+  }
+
+  // Sort atoms needing debug notes by file ordinal, then atom ordinal.
+  std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(),
+            [](const DefinedAtom *lhs, const DefinedAtom *rhs) {
+              if (lhs->file().ordinal() != rhs->file().ordinal())
+                return (lhs->file().ordinal() < rhs->file().ordinal());
+              return (lhs->ordinal() < rhs->ordinal());
+            });
+
+  // FIXME: Handle <rdar://problem/17689030>: Add -add_ast_path option to \
+  //        linker which add N_AST stab entry to output
+  // See OutputFile::synthesizeDebugNotes in ObjectFile.cpp in ld64.
+
+  StringRef oldFileName = "";
+  StringRef oldDirPath = "";
+  bool wroteStartSO = false;
+  std::unordered_set<std::string> seenFiles;
+  for (const DefinedAtom *atom : atomsNeedingDebugNotes) {
+    const auto &atomFile = cast<mach_o::MachOFile>(atom->file());
+    assert(dyn_cast_or_null<lld::mach_o::DwarfDebugInfo>(atomFile.debugInfo())
+           && "file for atom needing debug notes does not contain dwarf");
+    auto &dwarf = cast<lld::mach_o::DwarfDebugInfo>(*atomFile.debugInfo());
+
+    auto &tu = dwarf.translationUnitSource();
+    StringRef newFileName = tu.name;
+    StringRef newDirPath = tu.path;
+
+    // Add an SO whenever the TU source file changes.
+    if (newFileName != oldFileName || newDirPath != oldDirPath) {
+      // Translation unit change, emit ending SO
+      if (oldFileName != "")
+        _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, ""));
+
+      oldFileName = newFileName;
+      oldDirPath = newDirPath;
+
+      // If newDirPath doesn't end with a '/' we need to add one:
+      if (newDirPath.back() != '/') {
+        char *p =
+          file.ownedAllocations.Allocate<char>(newDirPath.size() + 2);
+        memcpy(p, newDirPath.data(), newDirPath.size());
+        p[newDirPath.size()] = '/';
+        p[newDirPath.size() + 1] = '\0';
+        newDirPath = p;
+      }
+
+      // New translation unit, emit start SOs:
+      _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newDirPath));
+      _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newFileName));
+
+      // Synthesize OSO for start of file.
+      char *fullPath = nullptr;
+      {
+        SmallString<1024> pathBuf(atomFile.path());
+        if (auto EC = llvm::sys::fs::make_absolute(pathBuf))
+          return llvm::errorCodeToError(EC);
+        fullPath = file.ownedAllocations.Allocate<char>(pathBuf.size() + 1);
+        memcpy(fullPath, pathBuf.c_str(), pathBuf.size() + 1);
+      }
+
+      // Get mod time.
+      uint32_t modTime = 0;
+      llvm::sys::fs::file_status stat;
+      if (!llvm::sys::fs::status(fullPath, stat))
+        if (llvm::sys::fs::exists(stat))
+          modTime = llvm::sys::toTimeT(stat.getLastModificationTime());
+
+      _stabs.push_back(mach_o::Stab(nullptr, N_OSO, _ctx.getCPUSubType(), 1,
+                                    modTime, fullPath));
+      // <rdar://problem/6337329> linker should put cpusubtype in n_sect field
+      // of nlist entry for N_OSO debug note entries.
+      wroteStartSO = true;
+    }
+
+    if (atom->contentType() == DefinedAtom::typeCode) {
+      // Synthesize BNSYM and start FUN stabs.
+      _stabs.push_back(mach_o::Stab(atom, N_BNSYM, 1, 0, 0, ""));
+      _stabs.push_back(mach_o::Stab(atom, N_FUN, 1, 0, 0, atom->name()));
+      // Synthesize any SOL stabs needed
+      // FIXME: add SOL stabs.
+      _stabs.push_back(mach_o::Stab(nullptr, N_FUN, 0, 0,
+                                    atom->rawContent().size(), ""));
+      _stabs.push_back(mach_o::Stab(nullptr, N_ENSYM, 1, 0,
+                                    atom->rawContent().size(), ""));
+    } else {
+      if (atom->scope() == Atom::scopeTranslationUnit)
+        _stabs.push_back(mach_o::Stab(atom, N_STSYM, 1, 0, 0, atom->name()));
+      else
+        _stabs.push_back(mach_o::Stab(nullptr, N_GSYM, 1, 0, 0, atom->name()));
+    }
+  }
+
+  // Emit ending SO if necessary.
+  if (wroteStartSO)
+    _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, ""));
+
+  // Copy any stabs from .o file.
+  for (const auto *objFile : filesWithStabs) {
+    const auto &stabsList =
+      cast<mach_o::StabsDebugInfo>(objFile->debugInfo())->stabs();
+    for (auto &stab : stabsList) {
+      // FIXME: Drop stabs whose atoms have been dead-stripped.
+      _stabs.push_back(stab);
+    }
+  }
+
+  return llvm::Error::success();
+}
+
+uint16_t Util::descBits(const DefinedAtom* atom) {
+  uint16_t desc = 0;
+  switch (atom->merge()) {
+  case lld::DefinedAtom::mergeNo:
+  case lld::DefinedAtom::mergeAsTentative:
+    break;
+  case lld::DefinedAtom::mergeAsWeak:
+  case lld::DefinedAtom::mergeAsWeakAndAddressUsed:
+    desc |= N_WEAK_DEF;
+    break;
+  case lld::DefinedAtom::mergeSameNameAndSize:
+  case lld::DefinedAtom::mergeByLargestSection:
+  case lld::DefinedAtom::mergeByContent:
+    llvm_unreachable("Unsupported DefinedAtom::merge()");
+    break;
+  }
+  if (atom->contentType() == lld::DefinedAtom::typeResolver)
+    desc |= N_SYMBOL_RESOLVER;
+  if (atom->contentType() == lld::DefinedAtom::typeMachHeader)
+    desc |= REFERENCED_DYNAMICALLY;
+  if (_archHandler.isThumbFunction(*atom))
+    desc |= N_ARM_THUMB_DEF;
+  if (atom->deadStrip() == DefinedAtom::deadStripNever &&
+      _ctx.outputMachOType() == llvm::MachO::MH_OBJECT) {
+    if ((atom->contentType() != DefinedAtom::typeInitializerPtr)
+     && (atom->contentType() != DefinedAtom::typeTerminatorPtr))
+    desc |= N_NO_DEAD_STRIP;
+  }
+  return desc;
+}
+
+bool Util::AtomSorter::operator()(const AtomAndIndex &left,
+                                  const AtomAndIndex &right) {
+  return (left.atom->name().compare(right.atom->name()) < 0);
+}
+
+llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom,
+                                       bool &inGlobalsRegion,
+                                       SymbolScope &scope) {
+  bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+  switch (atom->scope()) {
+  case Atom::scopeTranslationUnit:
+    scope = 0;
+    inGlobalsRegion = false;
+    return llvm::Error::success();
+  case Atom::scopeLinkageUnit:
+    if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) &&
+        _ctx.exportSymbolNamed(atom->name())) {
+      return llvm::make_error<GenericError>(
+                          Twine("cannot export hidden symbol ") + atom->name());
+    }
+    if (rMode) {
+      if (_ctx.keepPrivateExterns()) {
+        // -keep_private_externs means keep in globals region as N_PEXT.
+        scope = N_PEXT | N_EXT;
+        inGlobalsRegion = true;
+        return llvm::Error::success();
+      }
+    }
+    // scopeLinkageUnit symbols are no longer global once linked.
+    scope = N_PEXT;
+    inGlobalsRegion = false;
+    return llvm::Error::success();
+  case Atom::scopeGlobal:
+    if (_ctx.exportRestrictMode()) {
+      if (_ctx.exportSymbolNamed(atom->name())) {
+        scope = N_EXT;
+        inGlobalsRegion = true;
+        return llvm::Error::success();
+      } else {
+        scope = N_PEXT;
+        inGlobalsRegion = false;
+        return llvm::Error::success();
+      }
+    } else {
+      scope = N_EXT;
+      inGlobalsRegion = true;
+      return llvm::Error::success();
+    }
+    break;
+  }
+  llvm_unreachable("atom->scope() unknown enum value");
+}
+
+
+
+llvm::Error Util::addSymbols(const lld::File &atomFile,
+                             NormalizedFile &file) {
+  bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+  // Mach-O symbol table has four regions: stabs, locals, globals, undefs.
+
+  // Add all stabs.
+  for (auto &stab : _stabs) {
+    Symbol sym;
+    sym.type = static_cast<NListType>(stab.type);
+    sym.scope = 0;
+    sym.sect = stab.other;
+    sym.desc = stab.desc;
+    if (stab.atom)
+      sym.value = _atomToAddress[stab.atom];
+    else
+      sym.value = stab.value;
+    sym.name = stab.str;
+    file.stabsSymbols.push_back(sym);
+  }
+
+  // Add all local (non-global) symbols in address order
+  std::vector<AtomAndIndex> globals;
+  globals.reserve(512);
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      if (!atom->name().empty()) {
+        SymbolScope symbolScope;
+        bool inGlobalsRegion;
+        if (auto ec = getSymbolTableRegion(atom, inGlobalsRegion, symbolScope)){
+          return ec;
+        }
+        if (inGlobalsRegion) {
+          AtomAndIndex ai = { atom, sect->finalSectionIndex, symbolScope };
+          globals.push_back(ai);
+        } else {
+          Symbol sym;
+          sym.name  = atom->name();
+          sym.type  = N_SECT;
+          sym.scope = symbolScope;
+          sym.sect  = sect->finalSectionIndex;
+          sym.desc  = descBits(atom);
+          sym.value = _atomToAddress[atom];
+          _atomToSymbolIndex[atom] = file.localSymbols.size();
+          file.localSymbols.push_back(sym);
+        }
+      } else if (rMode && _archHandler.needsLocalSymbolInRelocatableFile(atom)){
+        // Create 'Lxxx' labels for anonymous atoms if archHandler says so.
+        static unsigned tempNum = 1;
+        char tmpName[16];
+        sprintf(tmpName, "L%04u", tempNum++);
+        StringRef tempRef(tmpName);
+        Symbol sym;
+        sym.name  = tempRef.copy(file.ownedAllocations);
+        sym.type  = N_SECT;
+        sym.scope = 0;
+        sym.sect  = sect->finalSectionIndex;
+        sym.desc  = 0;
+        sym.value = _atomToAddress[atom];
+        _atomToSymbolIndex[atom] = file.localSymbols.size();
+        file.localSymbols.push_back(sym);
+      }
+    }
+  }
+
+  // Sort global symbol alphabetically, then add to symbol table.
+  std::sort(globals.begin(), globals.end(), AtomSorter());
+  const uint32_t globalStartIndex = file.localSymbols.size();
+  for (AtomAndIndex &ai : globals) {
+    Symbol sym;
+    sym.name  = ai.atom->name();
+    sym.type  = N_SECT;
+    sym.scope = ai.scope;
+    sym.sect  = ai.index;
+    sym.desc  = descBits(static_cast<const DefinedAtom*>(ai.atom));
+    sym.value = _atomToAddress[ai.atom];
+    _atomToSymbolIndex[ai.atom] = globalStartIndex + file.globalSymbols.size();
+    file.globalSymbols.push_back(sym);
+  }
+
+  // Sort undefined symbol alphabetically, then add to symbol table.
+  std::vector<AtomAndIndex> undefs;
+  undefs.reserve(128);
+  for (const UndefinedAtom *atom : atomFile.undefined()) {
+    AtomAndIndex ai = { atom, 0, N_EXT };
+    undefs.push_back(ai);
+  }
+  for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) {
+    AtomAndIndex ai = { atom, 0, N_EXT };
+    undefs.push_back(ai);
+  }
+  std::sort(undefs.begin(), undefs.end(), AtomSorter());
+  const uint32_t start = file.globalSymbols.size() + file.localSymbols.size();
+  for (AtomAndIndex &ai : undefs) {
+    Symbol sym;
+    uint16_t desc = 0;
+    if (!rMode) {
+      uint8_t ordinal = 0;
+      if (!_ctx.useFlatNamespace())
+        ordinal = dylibOrdinal(dyn_cast<SharedLibraryAtom>(ai.atom));
+      llvm::MachO::SET_LIBRARY_ORDINAL(desc, ordinal);
+    }
+    sym.name  = ai.atom->name();
+    sym.type  = N_UNDF;
+    sym.scope = ai.scope;
+    sym.sect  = 0;
+    sym.desc  = desc;
+    sym.value = 0;
+    _atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start;
+    file.undefinedSymbols.push_back(sym);
+  }
+
+  return llvm::Error::success();
+}
+
+const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
+  for (const Reference *ref : *lpAtom) {
+    if (_archHandler.isLazyPointer(*ref)) {
+      return ref->target();
+    }
+  }
+  return nullptr;
+}
+
+const Atom *Util::targetOfStub(const DefinedAtom *stubAtom) {
+  for (const Reference *ref : *stubAtom) {
+    if (const Atom *ta = ref->target()) {
+      if (const DefinedAtom *lpAtom = dyn_cast<DefinedAtom>(ta)) {
+        const Atom *target = targetOfLazyPointer(lpAtom);
+        if (target)
+          return target;
+      }
+    }
+  }
+  return nullptr;
+}
+
+void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
+  for (SectionInfo *si : _sectionInfos) {
+    Section &normSect = file.sections[si->normalizedSectionIndex];
+    switch (si->type) {
+    case llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        bool foundTarget = false;
+        for (const Reference *ref : *info.atom) {
+          const Atom *target = ref->target();
+          if (target) {
+            if (isa<const SharedLibraryAtom>(target)) {
+              uint32_t index = _atomToSymbolIndex[target];
+              normSect.indirectSymbols.push_back(index);
+              foundTarget = true;
+            } else {
+              normSect.indirectSymbols.push_back(
+                                            llvm::MachO::INDIRECT_SYMBOL_LOCAL);
+            }
+          }
+        }
+        if (!foundTarget) {
+          normSect.indirectSymbols.push_back(
+                                             llvm::MachO::INDIRECT_SYMBOL_ABS);
+        }
+      }
+      break;
+    case llvm::MachO::S_LAZY_SYMBOL_POINTERS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        const Atom *target = targetOfLazyPointer(info.atom);
+        if (target) {
+          uint32_t index = _atomToSymbolIndex[target];
+          normSect.indirectSymbols.push_back(index);
+        }
+      }
+      break;
+    case llvm::MachO::S_SYMBOL_STUBS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        const Atom *target = targetOfStub(info.atom);
+        if (target) {
+          uint32_t index = _atomToSymbolIndex[target];
+          normSect.indirectSymbols.push_back(index);
+        }
+      }
+      break;
+    default:
+      break;
+    }
+  }
+}
+
+void Util::addDependentDylibs(const lld::File &atomFile,
+                              NormalizedFile &nFile) {
+  // Scan all imported symbols and build up list of dylibs they are from.
+  int ordinal = 1;
+  for (const auto *dylib : _ctx.allDylibs()) {
+    DylibPathToInfo::iterator pos = _dylibInfo.find(dylib->installName());
+    if (pos == _dylibInfo.end()) {
+      DylibInfo info;
+      bool flatNamespaceAtom = dylib == _ctx.flatNamespaceFile();
+
+      // If we're in -flat_namespace mode (or this atom came from the flat
+      // namespace file under -undefined dynamic_lookup) then use the flat
+      // lookup ordinal.
+      if (flatNamespaceAtom || _ctx.useFlatNamespace())
+        info.ordinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+      else
+        info.ordinal = ordinal++;
+      info.hasWeak = false;
+      info.hasNonWeak = !info.hasWeak;
+      _dylibInfo[dylib->installName()] = info;
+
+      // Unless this was a flat_namespace atom, record the source dylib.
+      if (!flatNamespaceAtom) {
+        DependentDylib depInfo;
+        depInfo.path = dylib->installName();
+        depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+        depInfo.currentVersion = _ctx.dylibCurrentVersion(dylib->path());
+        depInfo.compatVersion = _ctx.dylibCompatVersion(dylib->path());
+        nFile.dependentDylibs.push_back(depInfo);
+      }
+    } else {
+      pos->second.hasWeak = false;
+      pos->second.hasNonWeak = !pos->second.hasWeak;
+    }
+  }
+  // Automatically weak link dylib in which all symbols are weak (canBeNull).
+  for (DependentDylib &dep : nFile.dependentDylibs) {
+    DylibInfo &info = _dylibInfo[dep.path];
+    if (info.hasWeak && !info.hasNonWeak)
+      dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
+    else if (_ctx.isUpwardDylib(dep.path))
+      dep.kind = llvm::MachO::LC_LOAD_UPWARD_DYLIB;
+  }
+}
+
+int Util::dylibOrdinal(const SharedLibraryAtom *sa) {
+  return _dylibInfo[sa->loadName()].ordinal;
+}
+
+void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
+                                                  uint64_t &segmentStartAddr) {
+  segmentIndex = 0;
+  for (const SegmentInfo *seg : _segmentInfos) {
+    if ((seg->address <= sect->address)
+      && (seg->address+seg->size >= sect->address+sect->size)) {
+      segmentStartAddr = seg->address;
+      return;
+    }
+    ++segmentIndex;
+  }
+  llvm_unreachable("section not in any segment");
+}
+
+uint32_t Util::sectionIndexForAtom(const Atom *atom) {
+  uint64_t address = _atomToAddress[atom];
+  for (const SectionInfo *si : _sectionInfos) {
+    if ((si->address <= address) && (address < si->address+si->size))
+      return si->finalSectionIndex;
+  }
+  llvm_unreachable("atom not in any section");
+}
+
+void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
+  if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+    return;
+
+  // Utility function for ArchHandler to find symbol index for an atom.
+  auto symIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+    auto pos = _atomToSymbolIndex.find(&atom);
+    assert(pos != _atomToSymbolIndex.end());
+    return pos->second;
+  };
+
+  // Utility function for ArchHandler to find section index for an atom.
+  auto sectIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+    return sectionIndexForAtom(&atom);
+  };
+
+  // Utility function for ArchHandler to find address of atom in output file.
+  auto addressForAtom = [&] (const Atom &atom) -> uint64_t {
+    auto pos = _atomToAddress.find(&atom);
+    assert(pos != _atomToAddress.end());
+    return pos->second;
+  };
+
+  for (SectionInfo *si : _sectionInfos) {
+    Section &normSect = file.sections[si->normalizedSectionIndex];
+    for (const AtomInfo &info : si->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      for (const Reference *ref : *atom) {
+        // Skip emitting relocs for sections which are always able to be
+        // implicitly regenerated and where the relocation targets an address
+        // which is defined.
+        if (si->relocsToDefinedCanBeImplicit && isa<DefinedAtom>(ref->target()))
+          continue;
+        _archHandler.appendSectionRelocations(*atom, info.offsetInSection, *ref,
+                                              symIndexForAtom,
+                                              sectIndexForAtom,
+                                              addressForAtom,
+                                              normSect.relocations);
+      }
+    }
+  }
+}
+
+void Util::addFunctionStarts(const lld::File &, NormalizedFile &file) {
+  if (!_ctx.generateFunctionStartsLoadCommand())
+    return;
+  file.functionStarts.reserve(8192);
+  // Delta compress function starts, starting with the mach header symbol.
+  const uint64_t badAddress = ~0ULL;
+  uint64_t addr = badAddress;
+  for (SectionInfo *si : _sectionInfos) {
+    for (const AtomInfo &info : si->atomsAndOffsets) {
+      auto type = info.atom->contentType();
+      if (type == DefinedAtom::typeMachHeader) {
+        addr = _atomToAddress[info.atom];
+        continue;
+      }
+      if (type != DefinedAtom::typeCode)
+        continue;
+      assert(addr != badAddress && "Missing mach header symbol");
+      // Skip atoms which have 0 size.  This is so that LC_FUNCTION_STARTS
+      // can't spill in to the next section.
+      if (!info.atom->size())
+        continue;
+      uint64_t nextAddr = _atomToAddress[info.atom];
+      if (_archHandler.isThumbFunction(*info.atom))
+        nextAddr |= 1;
+      uint64_t delta = nextAddr - addr;
+      if (delta) {
+        ByteBuffer buffer;
+        buffer.append_uleb128(delta);
+        file.functionStarts.insert(file.functionStarts.end(), buffer.bytes(),
+                                   buffer.bytes() + buffer.size());
+      }
+      addr = nextAddr;
+    }
+  }
+
+  // Null terminate, and pad to pointer size for this arch.
+  file.functionStarts.push_back(0);
+
+  auto size = file.functionStarts.size();
+  for (unsigned i = size, e = llvm::alignTo(size, _ctx.is64Bit() ? 8 : 4);
+       i != e; ++i)
+    file.functionStarts.push_back(0);
+}
+
+void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) {
+  if (!_ctx.generateDataInCodeLoadCommand())
+    return;
+  for (SectionInfo *si : _sectionInfos) {
+    for (const AtomInfo &info : si->atomsAndOffsets) {
+      // Atoms that contain data-in-code have "transition" references
+      // which mark a point where the embedded data starts of ends.
+      // This needs to be converted to the mach-o format which is an array
+      // of data-in-code ranges.
+      uint32_t startOffset = 0;
+      DataRegionType mode = DataRegionType(0);
+      for (const Reference *ref : *info.atom) {
+        if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
+          continue;
+        if (_archHandler.isDataInCodeTransition(ref->kindValue())) {
+          DataRegionType nextMode = (DataRegionType)ref->addend();
+          if (mode != nextMode) {
+            if (mode != 0) {
+              // Found end data range, so make range entry.
+              DataInCode entry;
+              entry.offset = si->address + info.offsetInSection + startOffset;
+              entry.length = ref->offsetInAtom() - startOffset;
+              entry.kind   = mode;
+              file.dataInCode.push_back(entry);
+            }
+          }
+          mode = nextMode;
+          startOffset = ref->offsetInAtom();
+        }
+      }
+      if (mode != 0) {
+        // Function ends with data (no end transition).
+        DataInCode entry;
+        entry.offset = si->address + info.offsetInSection + startOffset;
+        entry.length = info.atom->size() - startOffset;
+        entry.kind   = mode;
+        file.dataInCode.push_back(entry);
+      }
+    }
+  }
+}
+
+void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
+                                                        NormalizedFile &nFile) {
+  if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
+    return;
+
+  uint8_t segmentIndex;
+  uint64_t segmentStartAddr;
+  for (SectionInfo *sect : _sectionInfos) {
+    segIndexForSection(sect, segmentIndex, segmentStartAddr);
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      for (const Reference *ref : *atom) {
+        uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
+                                - segmentStartAddr;
+        const Atom* targ = ref->target();
+        if (_archHandler.isPointer(*ref)) {
+          // A pointer to a DefinedAtom requires rebasing.
+          if (isa<DefinedAtom>(targ)) {
+            RebaseLocation rebase;
+            rebase.segIndex = segmentIndex;
+            rebase.segOffset = segmentOffset;
+            rebase.kind = llvm::MachO::REBASE_TYPE_POINTER;
+            nFile.rebasingInfo.push_back(rebase);
+          }
+          // A pointer to an SharedLibraryAtom requires binding.
+          if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
+            BindLocation bind;
+            bind.segIndex = segmentIndex;
+            bind.segOffset = segmentOffset;
+            bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+            bind.canBeNull = sa->canBeNullAtRuntime();
+            bind.ordinal = dylibOrdinal(sa);
+            bind.symbolName = targ->name();
+            bind.addend = ref->addend();
+            nFile.bindingInfo.push_back(bind);
+          }
+        }
+        else if (_archHandler.isLazyPointer(*ref)) {
+          BindLocation bind;
+          if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
+            bind.ordinal = dylibOrdinal(sa);
+          } else {
+            bind.ordinal = llvm::MachO::BIND_SPECIAL_DYLIB_SELF;
+          }
+          bind.segIndex = segmentIndex;
+          bind.segOffset = segmentOffset;
+          bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+          bind.canBeNull = false; //sa->canBeNullAtRuntime();
+          bind.symbolName = targ->name();
+          bind.addend = ref->addend();
+          nFile.lazyBindingInfo.push_back(bind);
+        }
+      }
+    }
+  }
+}
+
+void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
+  if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
+    return;
+
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      if (atom->scope() != Atom::scopeGlobal)
+        continue;
+      if (_ctx.exportRestrictMode()) {
+        if (!_ctx.exportSymbolNamed(atom->name()))
+          continue;
+      }
+      Export exprt;
+      exprt.name = atom->name();
+      exprt.offset = _atomToAddress[atom] - _ctx.baseAddress();
+      exprt.kind = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+      if (atom->merge() == DefinedAtom::mergeAsWeak)
+        exprt.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+      else
+        exprt.flags = 0;
+      exprt.otherOffset = 0;
+      exprt.otherName = StringRef();
+      nFile.exportInfo.push_back(exprt);
+    }
+  }
+}
+
+uint32_t Util::fileFlags() {
+  // FIXME: these need to determined at runtime.
+  if (_ctx.outputMachOType() == MH_OBJECT) {
+    return _subsectionsViaSymbols ? MH_SUBSECTIONS_VIA_SYMBOLS : 0;
+  } else {
+    uint32_t flags = MH_DYLDLINK;
+    if (!_ctx.useFlatNamespace())
+        flags |= MH_TWOLEVEL | MH_NOUNDEFS;
+    if ((_ctx.outputMachOType() == MH_EXECUTE) && _ctx.PIE())
+      flags |= MH_PIE;
+    if (_hasTLVDescriptors)
+      flags |= (MH_PIE | MH_HAS_TLV_DESCRIPTORS);
+    return flags;
+  }
+}
+
+} // end anonymous namespace
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+/// Convert a set of Atoms into a normalized mach-o file.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+normalizedFromAtoms(const lld::File &atomFile,
+                                           const MachOLinkingContext &context) {
+  // The util object buffers info until the normalized file can be made.
+  Util util(context);
+  util.processDefinedAtoms(atomFile);
+  util.organizeSections();
+
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+  NormalizedFile &normFile = *f.get();
+  normFile.arch = context.arch();
+  normFile.fileType = context.outputMachOType();
+  normFile.flags = util.fileFlags();
+  normFile.stackSize = context.stackSize();
+  normFile.installName = context.installName();
+  normFile.currentVersion = context.currentVersion();
+  normFile.compatVersion = context.compatibilityVersion();
+  normFile.os = context.os();
+
+  // If we are emitting an object file, then the min version is the maximum
+  // of the min's of all the source files and the cmdline.
+  if (normFile.fileType == llvm::MachO::MH_OBJECT)
+    normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion());
+  else
+    normFile.minOSverson = context.osMinVersion();
+
+  normFile.minOSVersionKind = util.minVersionCommandType();
+
+  normFile.sdkVersion = context.sdkVersion();
+  normFile.sourceVersion = context.sourceVersion();
+
+  if (context.generateVersionLoadCommand() &&
+      context.os() != MachOLinkingContext::OS::unknown)
+    normFile.hasMinVersionLoadCommand = true;
+  else if (normFile.fileType == llvm::MachO::MH_OBJECT &&
+           util.allSourceFilesHaveMinVersions() &&
+           ((normFile.os != MachOLinkingContext::OS::unknown) ||
+            util.minVersionCommandType())) {
+    // If we emit an object file, then it should contain a min version load
+    // command if all of the source files also contained min version commands.
+    // Also, we either need to have a platform, or found a platform from the
+    // source object files.
+    normFile.hasMinVersionLoadCommand = true;
+  }
+  normFile.generateDataInCodeLoadCommand =
+    context.generateDataInCodeLoadCommand();
+  normFile.pageSize = context.pageSize();
+  normFile.rpaths = context.rpaths();
+  util.addDependentDylibs(atomFile, normFile);
+  util.copySegmentInfo(normFile);
+  util.copySectionInfo(normFile);
+  util.assignAddressesToSections(normFile);
+  util.buildAtomToAddressMap();
+  if (auto err = util.synthesizeDebugNotes(normFile))
+    return std::move(err);
+  util.updateSectionInfo(normFile);
+  util.copySectionContent(normFile);
+  if (auto ec = util.addSymbols(atomFile, normFile)) {
+    return std::move(ec);
+  }
+  util.addIndirectSymbols(atomFile, normFile);
+  util.addRebaseAndBindingInfo(atomFile, normFile);
+  util.addExportInfo(atomFile, normFile);
+  util.addSectionRelocs(atomFile, normFile);
+  util.addFunctionStarts(atomFile, normFile);
+  util.buildDataInCodeArray(atomFile, normFile);
+  util.copyEntryPointAddress(normFile);
+
+  return std::move(f);
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
new file mode 100644 (file)
index 0000000..226a25d
--- /dev/null
@@ -0,0 +1,1635 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp --------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file Converts from in-memory normalized mach-o to in-memory Atoms.
+///
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+///                        |
+///                        |
+///                        v
+///                    +-------+
+///                    | Atoms |
+///                    +-------+
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+#define DEBUG_TYPE "normalized-file-to-atoms"
+
+namespace lld {
+namespace mach_o {
+
+
+namespace { // anonymous
+
+
+#define ENTRY(seg, sect, type, atomType) \
+  {seg, sect, type, DefinedAtom::atomType }
+
+struct MachORelocatableSectionToAtomType {
+  StringRef                 segmentName;
+  StringRef                 sectionName;
+  SectionType               sectionType;
+  DefinedAtom::ContentType  atomType;
+};
+
+const MachORelocatableSectionToAtomType sectsToAtomType[] = {
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeCode),
+  ENTRY("__TEXT", "__text",           S_REGULAR,          typeResolver),
+  ENTRY("__TEXT", "__cstring",        S_CSTRING_LITERALS, typeCString),
+  ENTRY("",       "",                 S_CSTRING_LITERALS, typeCString),
+  ENTRY("__TEXT", "__ustring",        S_REGULAR,          typeUTF16String),
+  ENTRY("__TEXT", "__const",          S_REGULAR,          typeConstant),
+  ENTRY("__TEXT", "__const_coal",     S_COALESCED,        typeConstant),
+  ENTRY("__TEXT", "__eh_frame",       S_COALESCED,        typeCFI),
+  ENTRY("__TEXT", "__eh_frame",       S_REGULAR,          typeCFI),
+  ENTRY("__TEXT", "__literal4",       S_4BYTE_LITERALS,   typeLiteral4),
+  ENTRY("__TEXT", "__literal8",       S_8BYTE_LITERALS,   typeLiteral8),
+  ENTRY("__TEXT", "__literal16",      S_16BYTE_LITERALS,  typeLiteral16),
+  ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR,          typeLSDA),
+  ENTRY("__DATA", "__data",           S_REGULAR,          typeData),
+  ENTRY("__DATA", "__datacoal_nt",    S_COALESCED,        typeData),
+  ENTRY("__DATA", "__const",          S_REGULAR,          typeConstData),
+  ENTRY("__DATA", "__cfstring",       S_REGULAR,          typeCFString),
+  ENTRY("__DATA", "__mod_init_func",  S_MOD_INIT_FUNC_POINTERS,
+                                                          typeInitializerPtr),
+  ENTRY("__DATA", "__mod_term_func",  S_MOD_TERM_FUNC_POINTERS,
+                                                          typeTerminatorPtr),
+  ENTRY("__DATA", "__got",            S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeGOT),
+  ENTRY("__DATA", "__bss",            S_ZEROFILL,         typeZeroFill),
+  ENTRY("",       "",                 S_NON_LAZY_SYMBOL_POINTERS,
+                                                          typeGOT),
+  ENTRY("__DATA", "__interposing",    S_INTERPOSING,      typeInterposingTuples),
+  ENTRY("__DATA", "__thread_vars",    S_THREAD_LOCAL_VARIABLES,
+                                                          typeThunkTLV),
+  ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData),
+  ENTRY("__DATA", "__thread_bss",     S_THREAD_LOCAL_ZEROFILL,
+                                                        typeTLVInitialZeroFill),
+  ENTRY("__DATA", "__objc_imageinfo", S_REGULAR,          typeObjCImageInfo),
+  ENTRY("__DATA", "__objc_catlist",   S_REGULAR,          typeObjC2CategoryList),
+  ENTRY("",       "",                 S_INTERPOSING,      typeInterposingTuples),
+  ENTRY("__LD",   "__compact_unwind", S_REGULAR,
+                                                         typeCompactUnwindInfo),
+  ENTRY("",       "",                 S_REGULAR,          typeUnknown)
+};
+#undef ENTRY
+
+
+/// Figures out ContentType of a mach-o section.
+DefinedAtom::ContentType atomTypeFromSection(const Section &section,
+                                             bool &customSectionName) {
+  // First look for match of name and type. Empty names in table are wildcards.
+  customSectionName = false;
+  for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
+                                 p->atomType != DefinedAtom::typeUnknown; ++p) {
+    if (p->sectionType != section.type)
+      continue;
+    if (!p->segmentName.equals(section.segmentName) && !p->segmentName.empty())
+      continue;
+    if (!p->sectionName.equals(section.sectionName) && !p->sectionName.empty())
+      continue;
+    customSectionName = p->segmentName.empty() && p->sectionName.empty();
+    return p->atomType;
+  }
+  // Look for code denoted by section attributes
+  if (section.attributes & S_ATTR_PURE_INSTRUCTIONS)
+    return DefinedAtom::typeCode;
+
+  return DefinedAtom::typeUnknown;
+}
+
+enum AtomizeModel {
+  atomizeAtSymbols,
+  atomizeFixedSize,
+  atomizePointerSize,
+  atomizeUTF8,
+  atomizeUTF16,
+  atomizeCFI,
+  atomizeCU,
+  atomizeCFString
+};
+
+/// Returns info on how to atomize a section of the specified ContentType.
+void sectionParseInfo(DefinedAtom::ContentType atomType,
+                      unsigned int &sizeMultiple,
+                      DefinedAtom::Scope &scope,
+                      DefinedAtom::Merge &merge,
+                      AtomizeModel &atomizeModel) {
+  struct ParseInfo {
+    DefinedAtom::ContentType  atomType;
+    unsigned int              sizeMultiple;
+    DefinedAtom::Scope        scope;
+    DefinedAtom::Merge        merge;
+    AtomizeModel              atomizeModel;
+  };
+
+  #define ENTRY(type, size, scope, merge, model) \
+    {DefinedAtom::type, size, DefinedAtom::scope, DefinedAtom::merge, model }
+
+  static const ParseInfo parseInfo[] = {
+    ENTRY(typeCode,              1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeData,              1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeConstData,         1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeZeroFill,          1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeConstant,          1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols),
+    ENTRY(typeCString,           1, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeUTF8),
+    ENTRY(typeUTF16String,       1, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeUTF16),
+    ENTRY(typeCFI,               4, scopeTranslationUnit, mergeNo,
+                                                            atomizeCFI),
+    ENTRY(typeLiteral4,          4, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeFixedSize),
+    ENTRY(typeLiteral8,          8, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeFixedSize),
+    ENTRY(typeLiteral16,        16, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeFixedSize),
+    ENTRY(typeCFString,          4, scopeLinkageUnit,     mergeByContent,
+                                                            atomizeCFString),
+    ENTRY(typeInitializerPtr,    4, scopeTranslationUnit, mergeNo,
+                                                            atomizePointerSize),
+    ENTRY(typeTerminatorPtr,     4, scopeTranslationUnit, mergeNo,
+                                                            atomizePointerSize),
+    ENTRY(typeCompactUnwindInfo, 4, scopeTranslationUnit, mergeNo,
+                                                            atomizeCU),
+    ENTRY(typeGOT,               4, scopeLinkageUnit,     mergeByContent,
+                                                            atomizePointerSize),
+    ENTRY(typeObjC2CategoryList, 4, scopeTranslationUnit, mergeByContent,
+                                                            atomizePointerSize),
+    ENTRY(typeUnknown,           1, scopeGlobal,          mergeNo,
+                                                            atomizeAtSymbols)
+  };
+  #undef ENTRY
+  const int tableLen = sizeof(parseInfo) / sizeof(ParseInfo);
+  for (int i=0; i < tableLen; ++i) {
+    if (parseInfo[i].atomType == atomType) {
+      sizeMultiple = parseInfo[i].sizeMultiple;
+      scope        = parseInfo[i].scope;
+      merge        = parseInfo[i].merge;
+      atomizeModel = parseInfo[i].atomizeModel;
+      return;
+    }
+  }
+
+  // Unknown type is atomized by symbols.
+  sizeMultiple = 1;
+  scope = DefinedAtom::scopeGlobal;
+  merge = DefinedAtom::mergeNo;
+  atomizeModel = atomizeAtSymbols;
+}
+
+
+Atom::Scope atomScope(uint8_t scope) {
+  switch (scope) {
+  case N_EXT:
+    return Atom::scopeGlobal;
+  case N_PEXT:
+  case N_PEXT | N_EXT:
+    return Atom::scopeLinkageUnit;
+  case 0:
+    return Atom::scopeTranslationUnit;
+  }
+  llvm_unreachable("unknown scope value!");
+}
+
+void appendSymbolsInSection(const std::vector<Symbol> &inSymbols,
+                            uint32_t sectionIndex,
+                            SmallVector<const Symbol *, 64> &outSyms) {
+  for (const Symbol &sym : inSymbols) {
+    // Only look at definition symbols.
+    if ((sym.type & N_TYPE) != N_SECT)
+      continue;
+    if (sym.sect != sectionIndex)
+      continue;
+    outSyms.push_back(&sym);
+  }
+}
+
+void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
+                    MachOFile &file, uint64_t symbolAddr, StringRef symbolName,
+                    uint16_t symbolDescFlags, Atom::Scope symbolScope,
+                    uint64_t nextSymbolAddr, bool scatterable, bool copyRefs) {
+  // Mach-O symbol table does have size in it. Instead the size is the
+  // difference between this and the next symbol.
+  uint64_t size = nextSymbolAddr - symbolAddr;
+  uint64_t offset = symbolAddr - section.address;
+  bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP) || !scatterable;
+  if (isZeroFillSection(section.type)) {
+    file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size,
+                                noDeadStrip, copyRefs, &section);
+  } else {
+    DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF)
+                              ? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo;
+    bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF);
+    if (atomType == DefinedAtom::typeUnknown) {
+      // Mach-O needs a segment and section name.  Concatentate those two
+      // with a / separator (e.g. "seg/sect") to fit into the lld model
+      // of just a section name.
+      std::string segSectName = section.segmentName.str()
+                                + "/" + section.sectionName.str();
+      file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType,
+                                         merge, thumb, noDeadStrip, offset,
+                                         size, segSectName, true, &section);
+    } else {
+      if ((atomType == lld::DefinedAtom::typeCode) &&
+          (symbolDescFlags & N_SYMBOL_RESOLVER)) {
+        atomType = lld::DefinedAtom::typeResolver;
+      }
+      file.addDefinedAtom(symbolName, symbolScope, atomType, merge,
+                          offset, size, thumb, noDeadStrip, copyRefs, &section);
+    }
+  }
+}
+
+llvm::Error processSymboledSection(DefinedAtom::ContentType atomType,
+                                   const Section &section,
+                                   const NormalizedFile &normalizedFile,
+                                   MachOFile &file, bool scatterable,
+                                   bool copyRefs) {
+  // Find section's index.
+  uint32_t sectIndex = 1;
+  for (auto &sect : normalizedFile.sections) {
+    if (&sect == &section)
+      break;
+    ++sectIndex;
+  }
+
+  // Find all symbols in this section.
+  SmallVector<const Symbol *, 64> symbols;
+  appendSymbolsInSection(normalizedFile.globalSymbols, sectIndex, symbols);
+  appendSymbolsInSection(normalizedFile.localSymbols,  sectIndex, symbols);
+
+  // Sort symbols.
+  std::sort(symbols.begin(), symbols.end(),
+            [](const Symbol *lhs, const Symbol *rhs) -> bool {
+              if (lhs == rhs)
+                return false;
+              // First by address.
+              uint64_t lhsAddr = lhs->value;
+              uint64_t rhsAddr = rhs->value;
+              if (lhsAddr != rhsAddr)
+                return lhsAddr < rhsAddr;
+               // If same address, one is an alias so sort by scope.
+              Atom::Scope lScope = atomScope(lhs->scope);
+              Atom::Scope rScope = atomScope(rhs->scope);
+              if (lScope != rScope)
+                return lScope < rScope;
+              // If same address and scope, see if one might be better as
+              // the alias.
+              bool lPrivate = (lhs->name.front() == 'l');
+              bool rPrivate = (rhs->name.front() == 'l');
+              if (lPrivate != rPrivate)
+                return lPrivate;
+              // If same address and scope, sort by name.
+              return lhs->name < rhs->name;
+            });
+
+  // Debug logging of symbols.
+  //for (const Symbol *sym : symbols)
+  //  llvm::errs() << "  sym: "
+  //    << llvm::format("0x%08llx ", (uint64_t)sym->value)
+  //    << ", " << sym->name << "\n";
+
+  // If section has no symbols and no content, there are no atoms.
+  if (symbols.empty() && section.content.empty())
+    return llvm::Error::success();
+
+  if (symbols.empty()) {
+    // Section has no symbols, put all content in one anoymous atom.
+    atomFromSymbol(atomType, section, file, section.address, StringRef(),
+                  0, Atom::scopeTranslationUnit,
+                  section.address + section.content.size(),
+                  scatterable, copyRefs);
+  }
+  else if (symbols.front()->value != section.address) {
+    // Section has anonymous content before first symbol.
+    atomFromSymbol(atomType, section, file, section.address, StringRef(),
+                   0, Atom::scopeTranslationUnit, symbols.front()->value,
+                   scatterable, copyRefs);
+  }
+
+  const Symbol *lastSym = nullptr;
+  for (const Symbol *sym : symbols) {
+    if (lastSym != nullptr) {
+      // Ignore any assembler added "ltmpNNN" symbol at start of section
+      // if there is another symbol at the start.
+      if ((lastSym->value != sym->value)
+          || lastSym->value != section.address
+          || !lastSym->name.startswith("ltmp")) {
+        atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
+                       lastSym->desc, atomScope(lastSym->scope), sym->value,
+                       scatterable, copyRefs);
+      }
+    }
+    lastSym = sym;
+  }
+  if (lastSym != nullptr) {
+    atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
+                   lastSym->desc, atomScope(lastSym->scope),
+                   section.address + section.content.size(),
+                   scatterable, copyRefs);
+  }
+
+  // If object built without .subsections_via_symbols, add reference chain.
+  if (!scatterable) {
+    MachODefinedAtom *prevAtom = nullptr;
+    file.eachAtomInSection(section,
+                           [&](MachODefinedAtom *atom, uint64_t offset)->void {
+      if (prevAtom)
+        prevAtom->addReference(Reference::KindNamespace::all,
+                               Reference::KindArch::all,
+                               Reference::kindLayoutAfter, 0, atom, 0);
+      prevAtom = atom;
+    });
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Error processSection(DefinedAtom::ContentType atomType,
+                           const Section &section,
+                           bool customSectionName,
+                           const NormalizedFile &normalizedFile,
+                           MachOFile &file, bool scatterable,
+                           bool copyRefs) {
+  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+
+  // Get info on how to atomize section.
+  unsigned int       sizeMultiple;
+  DefinedAtom::Scope scope;
+  DefinedAtom::Merge merge;
+  AtomizeModel       atomizeModel;
+  sectionParseInfo(atomType, sizeMultiple, scope, merge, atomizeModel);
+
+  // Validate section size.
+  if ((section.content.size() % sizeMultiple) != 0)
+    return llvm::make_error<GenericError>(Twine("Section ")
+                                          + section.segmentName
+                                          + "/" + section.sectionName
+                                          + " has size ("
+                                          + Twine(section.content.size())
+                                          + ") which is not a multiple of "
+                                          + Twine(sizeMultiple));
+
+  if (atomizeModel == atomizeAtSymbols) {
+    // Break section up into atoms each with a fixed size.
+    return processSymboledSection(atomType, section, normalizedFile, file,
+                                  scatterable, copyRefs);
+  } else {
+    unsigned int size;
+    for (unsigned int offset = 0, e = section.content.size(); offset != e;) {
+      switch (atomizeModel) {
+      case atomizeFixedSize:
+        // Break section up into atoms each with a fixed size.
+        size = sizeMultiple;
+        break;
+      case atomizePointerSize:
+        // Break section up into atoms each the size of a pointer.
+        size = is64 ? 8 : 4;
+        break;
+      case atomizeUTF8:
+        // Break section up into zero terminated c-strings.
+        size = 0;
+        for (unsigned int i = offset; i < e; ++i) {
+          if (section.content[i] == 0) {
+            size = i + 1 - offset;
+            break;
+          }
+        }
+        break;
+      case atomizeUTF16:
+        // Break section up into zero terminated UTF16 strings.
+        size = 0;
+        for (unsigned int i = offset; i < e; i += 2) {
+          if ((section.content[i] == 0) && (section.content[i + 1] == 0)) {
+            size = i + 2 - offset;
+            break;
+          }
+        }
+        break;
+      case atomizeCFI:
+        // Break section up into dwarf unwind CFIs (FDE or CIE).
+        size = read32(&section.content[offset], isBig) + 4;
+        if (offset+size > section.content.size()) {
+          return llvm::make_error<GenericError>(Twine("Section ")
+                                                + section.segmentName
+                                                + "/" + section.sectionName
+                                                + " is malformed.  Size of CFI "
+                                                "starting at offset ("
+                                                + Twine(offset)
+                                                + ") is past end of section.");
+        }
+        break;
+      case atomizeCU:
+        // Break section up into compact unwind entries.
+        size = is64 ? 32 : 20;
+        break;
+      case atomizeCFString:
+        // Break section up into NS/CFString objects.
+        size = is64 ? 32 : 16;
+        break;
+      case atomizeAtSymbols:
+        break;
+      }
+      if (size == 0) {
+        return llvm::make_error<GenericError>(Twine("Section ")
+                                              + section.segmentName
+                                              + "/" + section.sectionName
+                                              + " is malformed.  The last atom "
+                                              "is not zero terminated.");
+      }
+      if (customSectionName) {
+        // Mach-O needs a segment and section name.  Concatentate those two
+        // with a / separator (e.g. "seg/sect") to fit into the lld model
+        // of just a section name.
+        std::string segSectName = section.segmentName.str()
+                                  + "/" + section.sectionName.str();
+        file.addDefinedAtomInCustomSection(StringRef(), scope, atomType,
+                                           merge, false, false, offset,
+                                           size, segSectName, true, &section);
+      } else {
+        file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size,
+                            false, false, copyRefs, &section);
+      }
+      offset += size;
+    }
+  }
+  return llvm::Error::success();
+}
+
+const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile,
+                                          uint64_t address) {
+  for (const Section &s : normalizedFile.sections) {
+    uint64_t sAddr = s.address;
+    if ((sAddr <= address) && (address < sAddr+s.content.size())) {
+      return &s;
+    }
+  }
+  return nullptr;
+}
+
+const MachODefinedAtom *
+findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file,
+                        uint64_t addr, Reference::Addend &addend) {
+  const Section *sect = nullptr;
+  sect = findSectionCoveringAddress(normalizedFile, addr);
+  if (!sect)
+    return nullptr;
+
+  uint32_t offsetInTarget;
+  uint64_t offsetInSect = addr - sect->address;
+  auto atom =
+      file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
+  addend = offsetInTarget;
+  return atom;
+}
+
+// Walks all relocations for a section in a normalized .o file and
+// creates corresponding lld::Reference objects.
+llvm::Error convertRelocs(const Section &section,
+                          const NormalizedFile &normalizedFile,
+                          bool scatterable,
+                          MachOFile &file,
+                          ArchHandler &handler) {
+  // Utility function for ArchHandler to find atom by its address.
+  auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
+                         const lld::Atom **atom, Reference::Addend *addend)
+                         -> llvm::Error {
+    if (sectIndex > normalizedFile.sections.size())
+      return llvm::make_error<GenericError>(Twine("out of range section "
+                                     "index (") + Twine(sectIndex) + ")");
+    const Section *sect = nullptr;
+    if (sectIndex == 0) {
+      sect = findSectionCoveringAddress(normalizedFile, addr);
+      if (!sect)
+        return llvm::make_error<GenericError>(Twine("address (" + Twine(addr)
+                                       + ") is not in any section"));
+    } else {
+      sect = &normalizedFile.sections[sectIndex-1];
+    }
+    uint32_t offsetInTarget;
+    uint64_t offsetInSect = addr - sect->address;
+    *atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
+    *addend = offsetInTarget;
+    return llvm::Error::success();
+  };
+
+  // Utility function for ArchHandler to find atom by its symbol index.
+  auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
+                           -> llvm::Error {
+    // Find symbol from index.
+    const Symbol *sym = nullptr;
+    uint32_t numStabs  = normalizedFile.stabsSymbols.size();
+    uint32_t numLocal  = normalizedFile.localSymbols.size();
+    uint32_t numGlobal = normalizedFile.globalSymbols.size();
+    uint32_t numUndef  = normalizedFile.undefinedSymbols.size();
+    assert(symbolIndex >= numStabs && "Searched for stab via atomBySymbol?");
+    if (symbolIndex < numStabs+numLocal) {
+      sym = &normalizedFile.localSymbols[symbolIndex-numStabs];
+    } else if (symbolIndex < numStabs+numLocal+numGlobal) {
+      sym = &normalizedFile.globalSymbols[symbolIndex-numStabs-numLocal];
+    } else if (symbolIndex < numStabs+numLocal+numGlobal+numUndef) {
+      sym = &normalizedFile.undefinedSymbols[symbolIndex-numStabs-numLocal-
+                                             numGlobal];
+    } else {
+      return llvm::make_error<GenericError>(Twine("symbol index (")
+                                     + Twine(symbolIndex) + ") out of range");
+    }
+
+    // Find atom from symbol.
+    if ((sym->type & N_TYPE) == N_SECT) {
+      if (sym->sect > normalizedFile.sections.size())
+        return llvm::make_error<GenericError>(Twine("symbol section index (")
+                                        + Twine(sym->sect) + ") out of range ");
+      const Section &symSection = normalizedFile.sections[sym->sect-1];
+      uint64_t targetOffsetInSect = sym->value - symSection.address;
+      MachODefinedAtom *target = file.findAtomCoveringAddress(symSection,
+                                                            targetOffsetInSect);
+      if (target) {
+        *result = target;
+        return llvm::Error::success();
+      }
+      return llvm::make_error<GenericError>("no atom found for defined symbol");
+    } else if ((sym->type & N_TYPE) == N_UNDF) {
+      const lld::Atom *target = file.findUndefAtom(sym->name);
+      if (target) {
+        *result = target;
+        return llvm::Error::success();
+      }
+      return llvm::make_error<GenericError>("no undefined atom found for sym");
+    } else {
+      // Search undefs
+      return llvm::make_error<GenericError>("no atom found for symbol");
+    }
+  };
+
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  // Use old-school iterator so that paired relocations can be grouped.
+  for (auto it=section.relocations.begin(), e=section.relocations.end();
+                                                                it != e; ++it) {
+    const Relocation &reloc = *it;
+    // Find atom this relocation is in.
+    if (reloc.offset > section.content.size())
+      return llvm::make_error<GenericError>(
+                                    Twine("r_address (") + Twine(reloc.offset)
+                                    + ") is larger than section size ("
+                                    + Twine(section.content.size()) + ")");
+    uint32_t offsetInAtom;
+    MachODefinedAtom *inAtom = file.findAtomCoveringAddress(section,
+                                                            reloc.offset,
+                                                            &offsetInAtom);
+    assert(inAtom && "r_address in range, should have found atom");
+    uint64_t fixupAddress = section.address + reloc.offset;
+
+    const lld::Atom *target = nullptr;
+    Reference::Addend addend = 0;
+    Reference::KindValue kind;
+    if (handler.isPairedReloc(reloc)) {
+      // Handle paired relocations together.
+      const Relocation &reloc2 = *++it;
+      auto relocErr = handler.getPairReferenceInfo(
+          reloc, reloc2, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
+          atomByAddr, atomBySymbol, &kind, &target, &addend);
+      if (relocErr) {
+        return handleErrors(std::move(relocErr),
+                            [&](std::unique_ptr<GenericError> GE) {
+          return llvm::make_error<GenericError>(
+            Twine("bad relocation (") + GE->getMessage()
+             + ") in section "
+             + section.segmentName + "/" + section.sectionName
+             + " (r1_address=" + Twine::utohexstr(reloc.offset)
+             + ", r1_type=" + Twine(reloc.type)
+             + ", r1_extern=" + Twine(reloc.isExtern)
+             + ", r1_length=" + Twine((int)reloc.length)
+             + ", r1_pcrel=" + Twine(reloc.pcRel)
+             + (!reloc.scattered ? (Twine(", r1_symbolnum=")
+                                    + Twine(reloc.symbol))
+                                 : (Twine(", r1_scattered=1, r1_value=")
+                                    + Twine(reloc.value)))
+             + ")"
+             + ", (r2_address=" + Twine::utohexstr(reloc2.offset)
+             + ", r2_type=" + Twine(reloc2.type)
+             + ", r2_extern=" + Twine(reloc2.isExtern)
+             + ", r2_length=" + Twine((int)reloc2.length)
+             + ", r2_pcrel=" + Twine(reloc2.pcRel)
+             + (!reloc2.scattered ? (Twine(", r2_symbolnum=")
+                                     + Twine(reloc2.symbol))
+                                  : (Twine(", r2_scattered=1, r2_value=")
+                                     + Twine(reloc2.value)))
+             + ")" );
+          });
+      }
+    }
+    else {
+      // Use ArchHandler to convert relocation record into information
+      // needed to instantiate an lld::Reference object.
+      auto relocErr = handler.getReferenceInfo(
+          reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr,
+          atomBySymbol, &kind, &target, &addend);
+      if (relocErr) {
+        return handleErrors(std::move(relocErr),
+                            [&](std::unique_ptr<GenericError> GE) {
+          return llvm::make_error<GenericError>(
+            Twine("bad relocation (") + GE->getMessage()
+             + ") in section "
+             + section.segmentName + "/" + section.sectionName
+             + " (r_address=" + Twine::utohexstr(reloc.offset)
+             + ", r_type=" + Twine(reloc.type)
+             + ", r_extern=" + Twine(reloc.isExtern)
+             + ", r_length=" + Twine((int)reloc.length)
+             + ", r_pcrel=" + Twine(reloc.pcRel)
+             + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
+                                 : (Twine(", r_scattered=1, r_value=")
+                                    + Twine(reloc.value)))
+             + ")" );
+          });
+      }
+    }
+    // Instantiate an lld::Reference object and add to its atom.
+    inAtom->addReference(Reference::KindNamespace::mach_o,
+                         handler.kindArch(),
+                         kind, offsetInAtom, target, addend);
+  }
+
+  return llvm::Error::success();
+}
+
+bool isDebugInfoSection(const Section &section) {
+  if ((section.attributes & S_ATTR_DEBUG) == 0)
+    return false;
+  return section.segmentName.equals("__DWARF");
+}
+
+static const Atom* findDefinedAtomByName(MachOFile &file, Twine name) {
+  std::string strName = name.str();
+  for (auto *atom : file.defined())
+    if (atom->name() == strName)
+      return atom;
+  return nullptr;
+}
+
+static StringRef copyDebugString(StringRef str, BumpPtrAllocator &alloc) {
+  char *strCopy = alloc.Allocate<char>(str.size() + 1);
+  memcpy(strCopy, str.data(), str.size());
+  strCopy[str.size()] = '\0';
+  return strCopy;
+}
+
+llvm::Error parseStabs(MachOFile &file,
+                       const NormalizedFile &normalizedFile,
+                       bool copyRefs) {
+
+  if (normalizedFile.stabsSymbols.empty())
+    return llvm::Error::success();
+
+  // FIXME: Kill this off when we can move to sane yaml parsing.
+  std::unique_ptr<BumpPtrAllocator> allocator;
+  if (copyRefs)
+    allocator = llvm::make_unique<BumpPtrAllocator>();
+
+  enum { start, inBeginEnd } state = start;
+
+  const Atom *currentAtom = nullptr;
+  uint64_t currentAtomAddress = 0;
+  StabsDebugInfo::StabsList stabsList;
+  for (const auto &stabSym : normalizedFile.stabsSymbols) {
+    Stab stab(nullptr, stabSym.type, stabSym.sect, stabSym.desc,
+              stabSym.value, stabSym.name);
+    switch (state) {
+    case start:
+      switch (static_cast<StabType>(stabSym.type)) {
+      case N_BNSYM:
+        state = inBeginEnd;
+        currentAtomAddress = stabSym.value;
+        Reference::Addend addend;
+        currentAtom = findAtomCoveringAddress(normalizedFile, file,
+                                              currentAtomAddress, addend);
+        if (addend != 0)
+          return llvm::make_error<GenericError>(
+                   "Non-zero addend for BNSYM '" + stabSym.name + "' in " +
+                   file.path());
+        if (currentAtom)
+          stab.atom = currentAtom;
+        else {
+          // FIXME: ld64 just issues a warning here - should we match that?
+          return llvm::make_error<GenericError>(
+                   "can't find atom for stabs BNSYM at " +
+                   Twine::utohexstr(stabSym.value) + " in " + file.path());
+        }
+        break;
+      case N_SO:
+      case N_OSO:
+        // Not associated with an atom, just copy.
+        if (copyRefs)
+          stab.str = copyDebugString(stabSym.name, *allocator);
+        else
+          stab.str = stabSym.name;
+        break;
+      case N_GSYM: {
+        auto colonIdx = stabSym.name.find(':');
+        if (colonIdx != StringRef::npos) {
+          StringRef name = stabSym.name.substr(0, colonIdx);
+          currentAtom = findDefinedAtomByName(file, "_" + name);
+          stab.atom = currentAtom;
+          if (copyRefs)
+            stab.str = copyDebugString(stabSym.name, *allocator);
+          else
+            stab.str = stabSym.name;
+        } else {
+          currentAtom = findDefinedAtomByName(file, stabSym.name);
+          stab.atom = currentAtom;
+          if (copyRefs)
+            stab.str = copyDebugString(stabSym.name, *allocator);
+          else
+            stab.str = stabSym.name;
+        }
+        if (stab.atom == nullptr)
+          return llvm::make_error<GenericError>(
+                   "can't find atom for N_GSYM stabs" + stabSym.name +
+                   " in " + file.path());
+        break;
+      }
+      case N_FUN:
+        return llvm::make_error<GenericError>(
+                 "old-style N_FUN stab '" + stabSym.name + "' unsupported");
+      default:
+        return llvm::make_error<GenericError>(
+                 "unrecognized stab symbol '" + stabSym.name + "'");
+      }
+      break;
+    case inBeginEnd:
+      stab.atom = currentAtom;
+      switch (static_cast<StabType>(stabSym.type)) {
+      case N_ENSYM:
+        state = start;
+        currentAtom = nullptr;
+        break;
+      case N_FUN:
+        // Just copy the string.
+        if (copyRefs)
+          stab.str = copyDebugString(stabSym.name, *allocator);
+        else
+          stab.str = stabSym.name;
+        break;
+      default:
+        return llvm::make_error<GenericError>(
+                 "unrecognized stab symbol '" + stabSym.name + "'");
+      }
+    }
+    llvm::dbgs() << "Adding to stabsList: " << stab << "\n";
+    stabsList.push_back(stab);
+  }
+
+  file.setDebugInfo(llvm::make_unique<StabsDebugInfo>(std::move(stabsList)));
+
+  // FIXME: Kill this off when we fix YAML memory ownership.
+  file.debugInfo()->setAllocator(std::move(allocator));
+
+  return llvm::Error::success();
+}
+
+static llvm::DataExtractor
+dataExtractorFromSection(const NormalizedFile &normalizedFile,
+                         const Section &S) {
+  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  StringRef SecData(reinterpret_cast<const char*>(S.content.data()),
+                    S.content.size());
+  return llvm::DataExtractor(SecData, !isBig, is64 ? 8 : 4);
+}
+
+// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+//        inspection" code if possible.
+static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData,
+                                  uint64_t abbrCode) {
+  uint64_t curCode;
+  uint32_t offset = 0;
+  while ((curCode = abbrevData.getULEB128(&offset)) != abbrCode) {
+    // Tag
+    abbrevData.getULEB128(&offset);
+    // DW_CHILDREN
+    abbrevData.getU8(&offset);
+    // Attributes
+    while (abbrevData.getULEB128(&offset) | abbrevData.getULEB128(&offset))
+      ;
+  }
+  return offset;
+}
+
+// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+//        inspection" code if possible.
+static Expected<const char *>
+getIndexedString(const NormalizedFile &normalizedFile,
+                 llvm::dwarf::Form form, llvm::DataExtractor infoData,
+                 uint32_t &infoOffset, const Section &stringsSection) {
+  if (form == llvm::dwarf::DW_FORM_string)
+   return infoData.getCStr(&infoOffset);
+  if (form != llvm::dwarf::DW_FORM_strp)
+    return llvm::make_error<GenericError>(
+        "string field encoded without DW_FORM_strp");
+  uint32_t stringOffset = infoData.getU32(&infoOffset);
+  llvm::DataExtractor stringsData =
+    dataExtractorFromSection(normalizedFile, stringsSection);
+  return stringsData.getCStr(&stringOffset);
+}
+
+// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+//        inspection" code if possible.
+static llvm::Expected<TranslationUnitSource>
+readCompUnit(const NormalizedFile &normalizedFile,
+             const Section &info,
+             const Section &abbrev,
+             const Section &strings,
+             StringRef path) {
+  // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+  //        inspection" code if possible.
+  uint32_t offset = 0;
+  llvm::dwarf::DwarfFormat Format = llvm::dwarf::DwarfFormat::DWARF32;
+  auto infoData = dataExtractorFromSection(normalizedFile, info);
+  uint32_t length = infoData.getU32(&offset);
+  if (length == 0xffffffff) {
+    Format = llvm::dwarf::DwarfFormat::DWARF64;
+    infoData.getU64(&offset);
+  }
+  else if (length > 0xffffff00)
+    return llvm::make_error<GenericError>("Malformed DWARF in " + path);
+
+  uint16_t version = infoData.getU16(&offset);
+
+  if (version < 2 || version > 4)
+    return llvm::make_error<GenericError>("Unsupported DWARF version in " +
+                                          path);
+
+  infoData.getU32(&offset); // Abbrev offset (should be zero)
+  uint8_t addrSize = infoData.getU8(&offset);
+
+  uint32_t abbrCode = infoData.getULEB128(&offset);
+  auto abbrevData = dataExtractorFromSection(normalizedFile, abbrev);
+  uint32_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode);
+  uint64_t tag = abbrevData.getULEB128(&abbrevOffset);
+  if (tag != llvm::dwarf::DW_TAG_compile_unit)
+    return llvm::make_error<GenericError>("top level DIE is not a compile unit");
+  // DW_CHILDREN
+  abbrevData.getU8(&abbrevOffset);
+  uint32_t name;
+  llvm::dwarf::Form form;
+  llvm::DWARFFormParams formParams = {version, addrSize, Format};
+  TranslationUnitSource tu;
+  while ((name = abbrevData.getULEB128(&abbrevOffset)) |
+         (form = static_cast<llvm::dwarf::Form>(
+             abbrevData.getULEB128(&abbrevOffset))) &&
+         (name != 0 || form != 0)) {
+    switch (name) {
+    case llvm::dwarf::DW_AT_name: {
+      if (auto eName = getIndexedString(normalizedFile, form, infoData, offset,
+                                        strings))
+          tu.name = *eName;
+      else
+        return eName.takeError();
+      break;
+    }
+    case llvm::dwarf::DW_AT_comp_dir: {
+      if (auto eName = getIndexedString(normalizedFile, form, infoData, offset,
+                                        strings))
+        tu.path = *eName;
+      else
+        return eName.takeError();
+      break;
+    }
+    default:
+      llvm::DWARFFormValue::skipValue(form, infoData, &offset, formParams);
+    }
+  }
+  return tu;
+}
+
+llvm::Error parseDebugInfo(MachOFile &file,
+                           const NormalizedFile &normalizedFile, bool copyRefs) {
+
+  // Find the interesting debug info sections.
+  const Section *debugInfo = nullptr;
+  const Section *debugAbbrev = nullptr;
+  const Section *debugStrings = nullptr;
+
+  for (auto &s : normalizedFile.sections) {
+    if (s.segmentName == "__DWARF") {
+      if (s.sectionName == "__debug_info")
+        debugInfo = &s;
+      else if (s.sectionName == "__debug_abbrev")
+        debugAbbrev = &s;
+      else if (s.sectionName == "__debug_str")
+        debugStrings = &s;
+    }
+  }
+
+  if (!debugInfo)
+    return parseStabs(file, normalizedFile, copyRefs);
+
+  if (debugInfo->content.size() == 0)
+    return llvm::Error::success();
+
+  if (debugInfo->content.size() < 12)
+    return llvm::make_error<GenericError>("Malformed __debug_info section in " +
+                                          file.path() + ": too small");
+
+  if (!debugAbbrev)
+    return llvm::make_error<GenericError>("Missing __dwarf_abbrev section in " +
+                                          file.path());
+
+  if (auto tuOrErr = readCompUnit(normalizedFile, *debugInfo, *debugAbbrev,
+                                  *debugStrings, file.path())) {
+    // FIXME: Kill of allocator and code under 'copyRefs' when we fix YAML
+    //        memory ownership.
+    std::unique_ptr<BumpPtrAllocator> allocator;
+    if (copyRefs) {
+      allocator = llvm::make_unique<BumpPtrAllocator>();
+      tuOrErr->name = copyDebugString(tuOrErr->name, *allocator);
+      tuOrErr->path = copyDebugString(tuOrErr->path, *allocator);
+    }
+    file.setDebugInfo(llvm::make_unique<DwarfDebugInfo>(std::move(*tuOrErr)));
+    if (copyRefs)
+      file.debugInfo()->setAllocator(std::move(allocator));
+  } else
+    return tuOrErr.takeError();
+
+  return llvm::Error::success();
+}
+
+static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
+  if (is64)
+    return read64(addr, isBig);
+
+  int32_t res = read32(addr, isBig);
+  return res;
+}
+
+/// --- Augmentation String Processing ---
+
+struct CIEInfo {
+  bool _augmentationDataPresent = false;
+  bool _mayHaveEH = false;
+  uint32_t _offsetOfLSDA = ~0U;
+  uint32_t _offsetOfPersonality = ~0U;
+  uint32_t _offsetOfFDEPointerEncoding = ~0U;
+  uint32_t _augmentationDataLength = ~0U;
+};
+
+typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap;
+
+static llvm::Error processAugmentationString(const uint8_t *augStr,
+                                             CIEInfo &cieInfo,
+                                             unsigned &len) {
+
+  if (augStr[0] == '\0') {
+    len = 1;
+    return llvm::Error::success();
+  }
+
+  if (augStr[0] != 'z')
+    return llvm::make_error<GenericError>("expected 'z' at start of "
+                                          "augmentation string");
+
+  cieInfo._augmentationDataPresent = true;
+  uint64_t idx = 1;
+
+  uint32_t offsetInAugmentationData = 0;
+  while (augStr[idx] != '\0') {
+    if (augStr[idx] == 'L') {
+      cieInfo._offsetOfLSDA = offsetInAugmentationData;
+      // This adds a single byte to the augmentation data.
+      ++offsetInAugmentationData;
+      ++idx;
+      continue;
+    }
+    if (augStr[idx] == 'P') {
+      cieInfo._offsetOfPersonality = offsetInAugmentationData;
+      // This adds a single byte to the augmentation data for the encoding,
+      // then a number of bytes for the pointer data.
+      // FIXME: We are assuming 4 is correct here for the pointer size as we
+      // always currently use delta32ToGOT.
+      offsetInAugmentationData += 5;
+      ++idx;
+      continue;
+    }
+    if (augStr[idx] == 'R') {
+      cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData;
+      // This adds a single byte to the augmentation data.
+      ++offsetInAugmentationData;
+      ++idx;
+      continue;
+    }
+    if (augStr[idx] == 'e') {
+      if (augStr[idx + 1] != 'h')
+        return llvm::make_error<GenericError>("expected 'eh' in "
+                                              "augmentation string");
+      cieInfo._mayHaveEH = true;
+      idx += 2;
+      continue;
+    }
+    ++idx;
+  }
+
+  cieInfo._augmentationDataLength = offsetInAugmentationData;
+
+  len = idx + 1;
+  return llvm::Error::success();
+}
+
+static llvm::Error processCIE(const NormalizedFile &normalizedFile,
+                              MachOFile &file,
+                              mach_o::ArchHandler &handler,
+                              const Section *ehFrameSection,
+                              MachODefinedAtom *atom,
+                              uint64_t offset,
+                              CIEInfoMap &cieInfos) {
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  const uint8_t *frameData = atom->rawContent().data();
+
+  CIEInfo cieInfo;
+
+  uint32_t size = read32(frameData, isBig);
+  uint64_t cieIDField = size == 0xffffffffU
+                          ? sizeof(uint32_t) + sizeof(uint64_t)
+                          : sizeof(uint32_t);
+  uint64_t versionField = cieIDField + sizeof(uint32_t);
+  uint64_t augmentationStringField = versionField + sizeof(uint8_t);
+
+  unsigned augmentationStringLength = 0;
+  if (auto err = processAugmentationString(frameData + augmentationStringField,
+                                           cieInfo, augmentationStringLength))
+    return err;
+
+  if (cieInfo._offsetOfPersonality != ~0U) {
+    // If we have augmentation data for the personality function, then we may
+    // need to implicitly generate its relocation.
+
+    // Parse the EH Data field which is pointer sized.
+    uint64_t EHDataField = augmentationStringField + augmentationStringLength;
+    const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+    unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0);
+
+    // Parse Code Align Factor which is a ULEB128.
+    uint64_t CodeAlignField = EHDataField + EHDataFieldSize;
+    unsigned lengthFieldSize = 0;
+    llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize);
+
+    // Parse Data Align Factor which is a SLEB128.
+    uint64_t DataAlignField = CodeAlignField + lengthFieldSize;
+    llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize);
+
+    // Parse Return Address Register which is a byte.
+    uint64_t ReturnAddressField = DataAlignField + lengthFieldSize;
+
+    // Parse the augmentation length which is a ULEB128.
+    uint64_t AugmentationLengthField = ReturnAddressField + 1;
+    uint64_t AugmentationLength =
+      llvm::decodeULEB128(frameData + AugmentationLengthField,
+                          &lengthFieldSize);
+
+    if (AugmentationLength != cieInfo._augmentationDataLength)
+      return llvm::make_error<GenericError>("CIE augmentation data length "
+                                            "mismatch");
+
+    // Get the start address of the augmentation data.
+    uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize;
+
+    // Parse the personality function from the augmentation data.
+    uint64_t PersonalityField =
+      AugmentationDataField + cieInfo._offsetOfPersonality;
+
+    // Parse the personality encoding.
+    // FIXME: Verify that this is a 32-bit pcrel offset.
+    uint64_t PersonalityFunctionField = PersonalityField + 1;
+
+    if (atom->begin() != atom->end()) {
+      // If we have an explicit relocation, then make sure it matches this
+      // offset as this is where we'd expect it to be applied to.
+      DefinedAtom::reference_iterator CurrentRef = atom->begin();
+      if (CurrentRef->offsetInAtom() != PersonalityFunctionField)
+        return llvm::make_error<GenericError>("CIE personality reloc at "
+                                              "wrong offset");
+
+      if (++CurrentRef != atom->end())
+        return llvm::make_error<GenericError>("CIE contains too many relocs");
+    } else {
+      // Implicitly generate the personality function reloc.  It's assumed to
+      // be a delta32 offset to a GOT entry.
+      // FIXME: Parse the encoding and check this.
+      int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig);
+      uint64_t funcAddress = ehFrameSection->address + offset +
+                             PersonalityFunctionField;
+      funcAddress += funcDelta;
+
+      const MachODefinedAtom *func = nullptr;
+      Reference::Addend addend;
+      func = findAtomCoveringAddress(normalizedFile, file, funcAddress,
+                                     addend);
+      atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+                         handler.unwindRefToPersonalityFunctionKind(),
+                         PersonalityFunctionField, func, addend);
+    }
+  } else if (atom->begin() != atom->end()) {
+    // Otherwise, we expect there to be no relocations in this atom as the only
+    // relocation would have been to the personality function.
+    return llvm::make_error<GenericError>("unexpected relocation in CIE");
+  }
+
+
+  cieInfos[atom] = std::move(cieInfo);
+
+  return llvm::Error::success();
+}
+
+static llvm::Error processFDE(const NormalizedFile &normalizedFile,
+                              MachOFile &file,
+                              mach_o::ArchHandler &handler,
+                              const Section *ehFrameSection,
+                              MachODefinedAtom *atom,
+                              uint64_t offset,
+                              const CIEInfoMap &cieInfos) {
+
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+
+  // Compiler wasn't lazy and actually told us what it meant.
+  // Unfortunately, the compiler may not have generated references for all of
+  // [cie, func, lsda] and so we still need to parse the FDE and add references
+  // for any the compiler didn't generate.
+  if (atom->begin() != atom->end())
+    atom->sortReferences();
+
+  DefinedAtom::reference_iterator CurrentRef = atom->begin();
+
+  // This helper returns the reference (if one exists) at the offset we are
+  // currently processing.  It automatically increments the ref iterator if we
+  // do return a ref, and throws an error if we pass over a ref without
+  // comsuming it.
+  auto currentRefGetter = [&CurrentRef,
+                           &atom](uint64_t Offset)->const Reference* {
+    // If there are no more refs found, then we are done.
+    if (CurrentRef == atom->end())
+      return nullptr;
+
+    const Reference *Ref = *CurrentRef;
+
+    // If we haven't reached the offset for this reference, then return that
+    // we don't yet have a reference to process.
+    if (Offset < Ref->offsetInAtom())
+      return nullptr;
+
+    // If the offset is equal, then we want to process this ref.
+    if (Offset == Ref->offsetInAtom()) {
+      ++CurrentRef;
+      return Ref;
+    }
+
+    // The current ref is at an offset which is earlier than the current
+    // offset, then we failed to consume it when we should have.  In this case
+    // throw an error.
+    llvm::report_fatal_error("Skipped reference when processing FDE");
+  };
+
+  // Helper to either get the reference at this current location, and verify
+  // that it is of the expected type, or add a reference of that type.
+  // Returns the reference target.
+  auto verifyOrAddReference = [&](uint64_t targetAddress,
+                                  Reference::KindValue refKind,
+                                  uint64_t refAddress,
+                                  bool allowsAddend)->const Atom* {
+    if (auto *ref = currentRefGetter(refAddress)) {
+      // The compiler already emitted a relocation for the CIE ref.  This should
+      // have been converted to the correct type of reference in
+      // get[Pair]ReferenceInfo().
+      assert(ref->kindValue() == refKind &&
+             "Incorrect EHFrame reference kind");
+      return ref->target();
+    }
+    Reference::Addend addend;
+    auto *target = findAtomCoveringAddress(normalizedFile, file,
+                                           targetAddress, addend);
+    atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+                       refKind, refAddress, target, addend);
+
+    if (!allowsAddend)
+      assert(!addend && "EHFrame reference cannot have addend");
+    return target;
+  };
+
+  const uint8_t *startFrameData = atom->rawContent().data();
+  const uint8_t *frameData = startFrameData;
+
+  uint32_t size = read32(frameData, isBig);
+  uint64_t cieFieldInFDE = size == 0xffffffffU
+    ? sizeof(uint32_t) + sizeof(uint64_t)
+    : sizeof(uint32_t);
+
+  // Linker needs to fixup a reference from the FDE to its parent CIE (a
+  // 32-bit byte offset backwards in the __eh_frame section).
+  uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
+  uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
+  cieAddress -= cieDelta;
+
+  auto *cieRefTarget = verifyOrAddReference(cieAddress,
+                                            handler.unwindRefToCIEKind(),
+                                            cieFieldInFDE, false);
+  const MachODefinedAtom *cie = dyn_cast<MachODefinedAtom>(cieRefTarget);
+  assert(cie && cie->contentType() == DefinedAtom::typeCFI &&
+         "FDE's CIE field does not point at the start of a CIE.");
+
+  const CIEInfo &cieInfo = cieInfos.find(cie)->second;
+
+  // Linker needs to fixup reference from the FDE to the function it's
+  // describing. FIXME: there are actually different ways to do this, and the
+  // particular method used is specified in the CIE's augmentation fields
+  // (hopefully)
+  uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
+
+  int64_t functionFromFDE = readSPtr(is64, isBig,
+                                     frameData + rangeFieldInFDE);
+  uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
+  rangeStart += functionFromFDE;
+
+  verifyOrAddReference(rangeStart,
+                       handler.unwindRefToFunctionKind(),
+                       rangeFieldInFDE, true);
+
+  // Handle the augmentation data if there is any.
+  if (cieInfo._augmentationDataPresent) {
+    // First process the augmentation data length field.
+    uint64_t augmentationDataLengthFieldInFDE =
+      rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t));
+    unsigned lengthFieldSize = 0;
+    uint64_t augmentationDataLength =
+      llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
+                          &lengthFieldSize);
+
+    if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) {
+
+      // Look at the augmentation data field.
+      uint64_t augmentationDataFieldInFDE =
+        augmentationDataLengthFieldInFDE + lengthFieldSize;
+
+      int64_t lsdaFromFDE = readSPtr(is64, isBig,
+                                     frameData + augmentationDataFieldInFDE);
+      uint64_t lsdaStart =
+        ehFrameSection->address + offset + augmentationDataFieldInFDE +
+        lsdaFromFDE;
+
+      verifyOrAddReference(lsdaStart,
+                           handler.unwindRefToFunctionKind(),
+                           augmentationDataFieldInFDE, true);
+    }
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile,
+                                 MachOFile &file,
+                                 mach_o::ArchHandler &handler) {
+
+  const Section *ehFrameSection = nullptr;
+  for (auto &section : normalizedFile.sections)
+    if (section.segmentName == "__TEXT" &&
+        section.sectionName == "__eh_frame") {
+      ehFrameSection = &section;
+      break;
+    }
+
+  // No __eh_frame so nothing to do.
+  if (!ehFrameSection)
+    return llvm::Error::success();
+
+  llvm::Error ehFrameErr = llvm::Error::success();
+  CIEInfoMap cieInfos;
+
+  file.eachAtomInSection(*ehFrameSection,
+                         [&](MachODefinedAtom *atom, uint64_t offset) -> void {
+    assert(atom->contentType() == DefinedAtom::typeCFI);
+
+    // Bail out if we've encountered an error.
+    if (ehFrameErr)
+      return;
+
+    const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+    if (ArchHandler::isDwarfCIE(isBig, atom))
+      ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection,
+                              atom, offset, cieInfos);
+    else
+      ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
+                              atom, offset, cieInfos);
+  });
+
+  return ehFrameErr;
+}
+
+llvm::Error parseObjCImageInfo(const Section &sect,
+                               const NormalizedFile &normalizedFile,
+                               MachOFile &file) {
+
+  //   struct objc_image_info  {
+  //           uint32_t        version;        // initially 0
+  //           uint32_t        flags;
+  //   };
+
+  ArrayRef<uint8_t> content = sect.content;
+  if (content.size() != 8)
+    return llvm::make_error<GenericError>(sect.segmentName + "/" +
+                                          sect.sectionName +
+                                          " in file " + file.path() +
+                                          " should be 8 bytes in size");
+
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  uint32_t version = read32(content.data(), isBig);
+  if (version)
+    return llvm::make_error<GenericError>(sect.segmentName + "/" +
+                                          sect.sectionName +
+                                          " in file " + file.path() +
+                                          " should have version=0");
+
+  uint32_t flags = read32(content.data() + 4, isBig);
+  if (flags & (MachOLinkingContext::objc_supports_gc |
+               MachOLinkingContext::objc_gc_only))
+    return llvm::make_error<GenericError>(sect.segmentName + "/" +
+                                          sect.sectionName +
+                                          " in file " + file.path() +
+                                          " uses GC.  This is not supported");
+
+  if (flags & MachOLinkingContext::objc_retainReleaseForSimulator)
+    file.setObjcConstraint(MachOLinkingContext::objc_retainReleaseForSimulator);
+  else
+    file.setObjcConstraint(MachOLinkingContext::objc_retainRelease);
+
+  file.setSwiftVersion((flags >> 8) & 0xFF);
+
+  return llvm::Error::success();
+}
+
+/// Converts normalized mach-o file into an lld::File and lld::Atoms.
+llvm::Expected<std::unique_ptr<lld::File>>
+objectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+              bool copyRefs) {
+  std::unique_ptr<MachOFile> file(new MachOFile(path));
+  if (auto ec = normalizedObjectToAtoms(file.get(), normalizedFile, copyRefs))
+    return std::move(ec);
+  return std::unique_ptr<File>(std::move(file));
+}
+
+llvm::Expected<std::unique_ptr<lld::File>>
+dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+             bool copyRefs) {
+  // Instantiate SharedLibraryFile object.
+  std::unique_ptr<MachODylibFile> file(new MachODylibFile(path));
+  if (auto ec = normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs))
+    return std::move(ec);
+  return std::unique_ptr<File>(std::move(file));
+}
+
+} // anonymous namespace
+
+namespace normalized {
+
+static bool isObjCImageInfo(const Section &sect) {
+  return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") ||
+    (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo");
+}
+
+llvm::Error
+normalizedObjectToAtoms(MachOFile *file,
+                        const NormalizedFile &normalizedFile,
+                        bool copyRefs) {
+  DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
+                    << file->path() << "\n");
+  bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
+
+  // Create atoms from each section.
+  for (auto &sect : normalizedFile.sections) {
+
+    // If this is a debug-info section parse it specially.
+    if (isDebugInfoSection(sect))
+      continue;
+
+    // If the file contains an objc_image_info struct, then we should parse the
+    // ObjC flags and Swift version.
+    if (isObjCImageInfo(sect)) {
+      if (auto ec = parseObjCImageInfo(sect, normalizedFile, *file))
+        return ec;
+      // We then skip adding atoms for this section as we use the ObjCPass to
+      // re-emit this data after it has been aggregated for all files.
+      continue;
+    }
+
+    bool customSectionName;
+    DefinedAtom::ContentType atomType = atomTypeFromSection(sect,
+                                                            customSectionName);
+    if (auto ec =  processSection(atomType, sect, customSectionName,
+                                  normalizedFile, *file, scatterable, copyRefs))
+      return ec;
+  }
+  // Create atoms from undefined symbols.
+  for (auto &sym : normalizedFile.undefinedSymbols) {
+    // Undefinded symbols with n_value != 0 are actually tentative definitions.
+    if (sym.value == Hex64(0)) {
+      file->addUndefinedAtom(sym.name, copyRefs);
+    } else {
+      file->addTentativeDefAtom(sym.name, atomScope(sym.scope), sym.value,
+                                DefinedAtom::Alignment(1 << (sym.desc >> 8)),
+                                copyRefs);
+    }
+  }
+
+  // Convert mach-o relocations to References
+  std::unique_ptr<mach_o::ArchHandler> handler
+                                     = ArchHandler::create(normalizedFile.arch);
+  for (auto &sect : normalizedFile.sections) {
+    if (isDebugInfoSection(sect))
+      continue;
+    if (llvm::Error ec = convertRelocs(sect, normalizedFile, scatterable,
+                                       *file, *handler))
+      return ec;
+  }
+
+  // Add additional arch-specific References
+  file->eachDefinedAtom([&](MachODefinedAtom* atom) -> void {
+    handler->addAdditionalReferences(*atom);
+  });
+
+  // Each __eh_frame section needs references to both __text (the function we're
+  // providing unwind info for) and itself (FDE -> CIE). These aren't
+  // represented in the relocations on some architectures, so we have to add
+  // them back in manually there.
+  if (auto ec = addEHFrameReferences(normalizedFile, *file, *handler))
+    return ec;
+
+  // Process mach-o data-in-code regions array. That information is encoded in
+  // atoms as References at each transition point.
+  unsigned nextIndex = 0;
+  for (const DataInCode &entry : normalizedFile.dataInCode) {
+    ++nextIndex;
+    const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset);
+    if (!s) {
+      return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE address ("
+                                                  + Twine(entry.offset)
+                                                  + ") is not in any section"));
+    }
+    uint64_t offsetInSect = entry.offset - s->address;
+    uint32_t offsetInAtom;
+    MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect,
+                                                           &offsetInAtom);
+    if (offsetInAtom + entry.length > atom->size()) {
+      return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE entry "
+                                                  "(offset="
+                                                  + Twine(entry.offset)
+                                                  + ", length="
+                                                  + Twine(entry.length)
+                                                  + ") crosses atom boundary."));
+    }
+    // Add reference that marks start of data-in-code.
+    atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+                       handler->dataInCodeTransitionStart(*atom),
+                       offsetInAtom, atom, entry.kind);
+
+    // Peek at next entry, if it starts where this one ends, skip ending ref.
+    if (nextIndex < normalizedFile.dataInCode.size()) {
+      const DataInCode &nextEntry = normalizedFile.dataInCode[nextIndex];
+      if (nextEntry.offset == (entry.offset + entry.length))
+        continue;
+    }
+
+    // If data goes to end of function, skip ending ref.
+    if ((offsetInAtom + entry.length) == atom->size())
+      continue;
+
+    // Add reference that marks end of data-in-code.
+    atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+                       handler->dataInCodeTransitionEnd(*atom),
+                       offsetInAtom+entry.length, atom, 0);
+  }
+
+  // Cache some attributes on the file for use later.
+  file->setFlags(normalizedFile.flags);
+  file->setArch(normalizedFile.arch);
+  file->setOS(normalizedFile.os);
+  file->setMinVersion(normalizedFile.minOSverson);
+  file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind);
+
+  // Sort references in each atom to their canonical order.
+  for (const DefinedAtom* defAtom : file->defined()) {
+    reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
+  }
+
+  if (auto err = parseDebugInfo(*file, normalizedFile, copyRefs))
+    return err;
+
+  return llvm::Error::success();
+}
+
+llvm::Error
+normalizedDylibToAtoms(MachODylibFile *file,
+                       const NormalizedFile &normalizedFile,
+                       bool copyRefs) {
+  file->setInstallName(normalizedFile.installName);
+  file->setCompatVersion(normalizedFile.compatVersion);
+  file->setCurrentVersion(normalizedFile.currentVersion);
+
+  // Tell MachODylibFile object about all symbols it exports.
+  if (!normalizedFile.exportInfo.empty()) {
+    // If exports trie exists, use it instead of traditional symbol table.
+    for (const Export &exp : normalizedFile.exportInfo) {
+      bool weakDef = (exp.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+      // StringRefs from export iterator are ephemeral, so force copy.
+      file->addExportedSymbol(exp.name, weakDef, true);
+    }
+  } else {
+    for (auto &sym : normalizedFile.globalSymbols) {
+      assert((sym.scope & N_EXT) && "only expect external symbols here");
+      bool weakDef = (sym.desc & N_WEAK_DEF);
+      file->addExportedSymbol(sym.name, weakDef, copyRefs);
+    }
+  }
+  // Tell MachODylibFile object about all dylibs it re-exports.
+  for (const DependentDylib &dep : normalizedFile.dependentDylibs) {
+    if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
+      file->addReExportedDylib(dep.path);
+  }
+  return llvm::Error::success();
+}
+
+void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
+                                          StringRef &segmentName,
+                                          StringRef &sectionName,
+                                          SectionType &sectionType,
+                                          SectionAttr &sectionAttrs,
+                                          bool &relocsToDefinedCanBeImplicit) {
+
+  for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
+                                 p->atomType != DefinedAtom::typeUnknown; ++p) {
+    if (p->atomType != atomType)
+      continue;
+    // Wild carded entries are ignored for reverse lookups.
+    if (p->segmentName.empty() || p->sectionName.empty())
+      continue;
+    segmentName = p->segmentName;
+    sectionName = p->sectionName;
+    sectionType = p->sectionType;
+    sectionAttrs = 0;
+    relocsToDefinedCanBeImplicit = false;
+    if (atomType == DefinedAtom::typeCode)
+      sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
+    if (atomType == DefinedAtom::typeCFI)
+      relocsToDefinedCanBeImplicit = true;
+    return;
+  }
+  llvm_unreachable("content type not yet supported");
+}
+
+llvm::Expected<std::unique_ptr<lld::File>>
+normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+                  bool copyRefs) {
+  switch (normalizedFile.fileType) {
+  case MH_DYLIB:
+  case MH_DYLIB_STUB:
+    return dylibToAtoms(normalizedFile, path, copyRefs);
+  case MH_OBJECT:
+    return objectToAtoms(normalizedFile, path, copyRefs);
+  default:
+    llvm_unreachable("unhandled MachO file type!");
+  }
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
new file mode 100644 (file)
index 0000000..5233e42
--- /dev/null
@@ -0,0 +1,843 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp -----------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation uses YAML I/O to
+/// provide the convert between YAML and the normalized mach-o (NM).
+///
+///                  +------------+         +------+
+///                  | normalized |   <->   | yaml |
+///                  +------------+         +------+
+
+#include "MachONormalizedFile.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/YamlContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+using llvm::StringRef;
+using namespace llvm::yaml;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+using lld::YamlContext;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Segment)
+LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
+LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
+LLVM_YAML_IS_SEQUENCE_VECTOR(DataInCode)
+
+
+// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
+namespace llvm {
+namespace yaml {
+
+// A vector of Sections is a sequence.
+template<>
+struct SequenceTraits< std::vector<Section> > {
+  static size_t size(IO &io, std::vector<Section> &seq) {
+    return seq.size();
+  }
+  static Section& element(IO &io, std::vector<Section> &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+template<>
+struct SequenceTraits< std::vector<Symbol> > {
+  static size_t size(IO &io, std::vector<Symbol> &seq) {
+    return seq.size();
+  }
+  static Symbol& element(IO &io, std::vector<Symbol> &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+// A vector of Relocations is a sequence.
+template<>
+struct SequenceTraits< Relocations > {
+  static size_t size(IO &io, Relocations &seq) {
+    return seq.size();
+  }
+  static Relocation& element(IO &io, Relocations &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+// The content for a section is represented as a flow sequence of hex bytes.
+template<>
+struct SequenceTraits< ContentBytes > {
+  static size_t size(IO &io, ContentBytes &seq) {
+    return seq.size();
+  }
+  static Hex8& element(IO &io, ContentBytes &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+  static const bool flow = true;
+};
+
+// The indirect symbols for a section is represented as a flow sequence
+// of numbers (symbol table indexes).
+template<>
+struct SequenceTraits< IndirectSymbols > {
+  static size_t size(IO &io, IndirectSymbols &seq) {
+    return seq.size();
+  }
+  static uint32_t& element(IO &io, IndirectSymbols &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+  static const bool flow = true;
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
+  static void enumeration(IO &io, lld::MachOLinkingContext::Arch &value) {
+    io.enumCase(value, "unknown",lld::MachOLinkingContext::arch_unknown);
+    io.enumCase(value, "ppc",    lld::MachOLinkingContext::arch_ppc);
+    io.enumCase(value, "x86",    lld::MachOLinkingContext::arch_x86);
+    io.enumCase(value, "x86_64", lld::MachOLinkingContext::arch_x86_64);
+    io.enumCase(value, "armv6",  lld::MachOLinkingContext::arch_armv6);
+    io.enumCase(value, "armv7",  lld::MachOLinkingContext::arch_armv7);
+    io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
+    io.enumCase(value, "arm64",  lld::MachOLinkingContext::arch_arm64);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> {
+  static void enumeration(IO &io, lld::MachOLinkingContext::OS &value) {
+    io.enumCase(value, "unknown",
+                          lld::MachOLinkingContext::OS::unknown);
+    io.enumCase(value, "Mac OS X",
+                          lld::MachOLinkingContext::OS::macOSX);
+    io.enumCase(value, "iOS",
+                          lld::MachOLinkingContext::OS::iOS);
+    io.enumCase(value, "iOS Simulator",
+                          lld::MachOLinkingContext::OS::iOS_simulator);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<HeaderFileType> {
+  static void enumeration(IO &io, HeaderFileType &value) {
+    io.enumCase(value, "MH_OBJECT",   llvm::MachO::MH_OBJECT);
+    io.enumCase(value, "MH_DYLIB",    llvm::MachO::MH_DYLIB);
+    io.enumCase(value, "MH_EXECUTE",  llvm::MachO::MH_EXECUTE);
+    io.enumCase(value, "MH_BUNDLE",   llvm::MachO::MH_BUNDLE);
+  }
+};
+
+
+template <>
+struct ScalarBitSetTraits<FileFlags> {
+  static void bitset(IO &io, FileFlags &value) {
+    io.bitSetCase(value, "MH_TWOLEVEL",
+                          llvm::MachO::MH_TWOLEVEL);
+    io.bitSetCase(value, "MH_SUBSECTIONS_VIA_SYMBOLS",
+                          llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<SectionType> {
+  static void enumeration(IO &io, SectionType &value) {
+    io.enumCase(value, "S_REGULAR",
+                        llvm::MachO::S_REGULAR);
+    io.enumCase(value, "S_ZEROFILL",
+                        llvm::MachO::S_ZEROFILL);
+    io.enumCase(value, "S_CSTRING_LITERALS",
+                        llvm::MachO::S_CSTRING_LITERALS);
+    io.enumCase(value, "S_4BYTE_LITERALS",
+                        llvm::MachO::S_4BYTE_LITERALS);
+    io.enumCase(value, "S_8BYTE_LITERALS",
+                        llvm::MachO::S_8BYTE_LITERALS);
+    io.enumCase(value, "S_LITERAL_POINTERS",
+                        llvm::MachO::S_LITERAL_POINTERS);
+    io.enumCase(value, "S_NON_LAZY_SYMBOL_POINTERS",
+                        llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS);
+    io.enumCase(value, "S_LAZY_SYMBOL_POINTERS",
+                        llvm::MachO::S_LAZY_SYMBOL_POINTERS);
+    io.enumCase(value, "S_SYMBOL_STUBS",
+                        llvm::MachO::S_SYMBOL_STUBS);
+    io.enumCase(value, "S_MOD_INIT_FUNC_POINTERS",
+                        llvm::MachO::S_MOD_INIT_FUNC_POINTERS);
+    io.enumCase(value, "S_MOD_TERM_FUNC_POINTERS",
+                        llvm::MachO::S_MOD_TERM_FUNC_POINTERS);
+    io.enumCase(value, "S_COALESCED",
+                        llvm::MachO::S_COALESCED);
+    io.enumCase(value, "S_GB_ZEROFILL",
+                        llvm::MachO::S_GB_ZEROFILL);
+    io.enumCase(value, "S_INTERPOSING",
+                        llvm::MachO::S_INTERPOSING);
+    io.enumCase(value, "S_16BYTE_LITERALS",
+                        llvm::MachO::S_16BYTE_LITERALS);
+    io.enumCase(value, "S_DTRACE_DOF",
+                        llvm::MachO::S_DTRACE_DOF);
+    io.enumCase(value, "S_LAZY_DYLIB_SYMBOL_POINTERS",
+                        llvm::MachO::S_LAZY_DYLIB_SYMBOL_POINTERS);
+    io.enumCase(value, "S_THREAD_LOCAL_REGULAR",
+                        llvm::MachO::S_THREAD_LOCAL_REGULAR);
+    io.enumCase(value, "S_THREAD_LOCAL_ZEROFILL",
+                        llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+    io.enumCase(value, "S_THREAD_LOCAL_VARIABLES",
+                        llvm::MachO::S_THREAD_LOCAL_VARIABLES);
+    io.enumCase(value, "S_THREAD_LOCAL_VARIABLE_POINTERS",
+                        llvm::MachO::S_THREAD_LOCAL_VARIABLE_POINTERS);
+    io.enumCase(value, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS",
+                        llvm::MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SectionAttr> {
+  static void bitset(IO &io, SectionAttr &value) {
+    io.bitSetCase(value, "S_ATTR_PURE_INSTRUCTIONS",
+                          llvm::MachO::S_ATTR_PURE_INSTRUCTIONS);
+    io.bitSetCase(value, "S_ATTR_SOME_INSTRUCTIONS",
+                          llvm::MachO::S_ATTR_SOME_INSTRUCTIONS);
+    io.bitSetCase(value, "S_ATTR_NO_DEAD_STRIP",
+                          llvm::MachO::S_ATTR_NO_DEAD_STRIP);
+    io.bitSetCase(value, "S_ATTR_EXT_RELOC",
+                          llvm::MachO::S_ATTR_EXT_RELOC);
+    io.bitSetCase(value, "S_ATTR_LOC_RELOC",
+                          llvm::MachO::S_ATTR_LOC_RELOC);
+    io.bitSetCase(value, "S_ATTR_DEBUG",
+                         llvm::MachO::S_ATTR_DEBUG);
+  }
+};
+
+/// This is a custom formatter for SectionAlignment.  Values are
+/// the power to raise by, ie, the n in 2^n.
+template <> struct ScalarTraits<SectionAlignment> {
+  static void output(const SectionAlignment &value, void *ctxt,
+                     raw_ostream &out) {
+    out << llvm::format("%d", (uint32_t)value);
+  }
+
+  static StringRef input(StringRef scalar, void *ctxt,
+                         SectionAlignment &value) {
+    uint32_t alignment;
+    if (scalar.getAsInteger(0, alignment)) {
+      return "malformed alignment value";
+    }
+    if (!llvm::isPowerOf2_32(alignment))
+      return "alignment must be a power of 2";
+    value = alignment;
+    return StringRef(); // returning empty string means success
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <>
+struct ScalarEnumerationTraits<NListType> {
+  static void enumeration(IO &io, NListType &value) {
+    io.enumCase(value, "N_UNDF",  llvm::MachO::N_UNDF);
+    io.enumCase(value, "N_ABS",   llvm::MachO::N_ABS);
+    io.enumCase(value, "N_SECT",  llvm::MachO::N_SECT);
+    io.enumCase(value, "N_PBUD",  llvm::MachO::N_PBUD);
+    io.enumCase(value, "N_INDR",  llvm::MachO::N_INDR);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolScope> {
+  static void bitset(IO &io, SymbolScope &value) {
+    io.bitSetCase(value, "N_EXT",   llvm::MachO::N_EXT);
+    io.bitSetCase(value, "N_PEXT",  llvm::MachO::N_PEXT);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolDesc> {
+  static void bitset(IO &io, SymbolDesc &value) {
+    io.bitSetCase(value, "N_NO_DEAD_STRIP",   llvm::MachO::N_NO_DEAD_STRIP);
+    io.bitSetCase(value, "N_WEAK_REF",        llvm::MachO::N_WEAK_REF);
+    io.bitSetCase(value, "N_WEAK_DEF",        llvm::MachO::N_WEAK_DEF);
+    io.bitSetCase(value, "N_ARM_THUMB_DEF",   llvm::MachO::N_ARM_THUMB_DEF);
+    io.bitSetCase(value, "N_SYMBOL_RESOLVER", llvm::MachO::N_SYMBOL_RESOLVER);
+  }
+};
+
+
+template <>
+struct MappingTraits<Section> {
+  struct NormalizedContentBytes;
+  static void mapping(IO &io, Section &sect) {
+    io.mapRequired("segment",         sect.segmentName);
+    io.mapRequired("section",         sect.sectionName);
+    io.mapRequired("type",            sect.type);
+    io.mapOptional("attributes",      sect.attributes);
+    io.mapOptional("alignment",       sect.alignment, (SectionAlignment)1);
+    io.mapRequired("address",         sect.address);
+    if (isZeroFillSection(sect.type)) {
+      // S_ZEROFILL sections use "size:" instead of "content:"
+      uint64_t size = sect.content.size();
+      io.mapOptional("size",          size);
+      if (!io.outputting()) {
+        uint8_t *bytes = nullptr;
+        sect.content = makeArrayRef(bytes, size);
+      }
+    } else {
+      MappingNormalization<NormalizedContent, ArrayRef<uint8_t>> content(
+        io, sect.content);
+      io.mapOptional("content",         content->_normalizedContent);
+    }
+    io.mapOptional("relocations",     sect.relocations);
+    io.mapOptional("indirect-syms",   sect.indirectSymbols);
+  }
+
+  struct NormalizedContent {
+    NormalizedContent(IO &io) : _io(io) {}
+    NormalizedContent(IO &io, ArrayRef<uint8_t> content) : _io(io) {
+      // When writing yaml, copy content byte array to Hex8 vector.
+      for (auto &c : content) {
+        _normalizedContent.push_back(c);
+      }
+    }
+    ArrayRef<uint8_t> denormalize(IO &io) {
+      // When reading yaml, allocate byte array owned by NormalizedFile and
+      // copy Hex8 vector to byte array.
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      NormalizedFile *file = info->_normalizeMachOFile;
+      assert(file != nullptr);
+      size_t size = _normalizedContent.size();
+      if (!size)
+        return None;
+      uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
+      std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
+      return makeArrayRef(bytes, size);
+    }
+
+    IO                &_io;
+    ContentBytes       _normalizedContent;
+  };
+};
+
+
+template <>
+struct MappingTraits<Relocation> {
+  static void mapping(IO &io, Relocation &reloc) {
+    io.mapRequired("offset",    reloc.offset);
+    io.mapOptional("scattered", reloc.scattered, false);
+    io.mapRequired("type",      reloc.type);
+    io.mapRequired("length",    reloc.length);
+    io.mapRequired("pc-rel",    reloc.pcRel);
+    if ( !reloc.scattered )
+     io.mapRequired("extern",   reloc.isExtern);
+    if ( reloc.scattered )
+     io.mapRequired("value",    reloc.value);
+    if ( !reloc.scattered )
+     io.mapRequired("symbol",   reloc.symbol);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<RelocationInfoType> {
+  static void enumeration(IO &io, RelocationInfoType &value) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    assert(info != nullptr);
+    NormalizedFile *file = info->_normalizeMachOFile;
+    assert(file != nullptr);
+    switch (file->arch) {
+    case lld::MachOLinkingContext::arch_x86_64:
+      io.enumCase(value, "X86_64_RELOC_UNSIGNED",
+                                  llvm::MachO::X86_64_RELOC_UNSIGNED);
+      io.enumCase(value, "X86_64_RELOC_SIGNED",
+                                  llvm::MachO::X86_64_RELOC_SIGNED);
+      io.enumCase(value, "X86_64_RELOC_BRANCH",
+                                  llvm::MachO::X86_64_RELOC_BRANCH);
+      io.enumCase(value, "X86_64_RELOC_GOT_LOAD",
+                                  llvm::MachO::X86_64_RELOC_GOT_LOAD);
+      io.enumCase(value, "X86_64_RELOC_GOT",
+                                  llvm::MachO::X86_64_RELOC_GOT);
+      io.enumCase(value, "X86_64_RELOC_SUBTRACTOR",
+                                  llvm::MachO::X86_64_RELOC_SUBTRACTOR);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_1",
+                                  llvm::MachO::X86_64_RELOC_SIGNED_1);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_2",
+                                  llvm::MachO::X86_64_RELOC_SIGNED_2);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_4",
+                                  llvm::MachO::X86_64_RELOC_SIGNED_4);
+      io.enumCase(value, "X86_64_RELOC_TLV",
+                                  llvm::MachO::X86_64_RELOC_TLV);
+      break;
+    case lld::MachOLinkingContext::arch_x86:
+      io.enumCase(value, "GENERIC_RELOC_VANILLA",
+                                  llvm::MachO::GENERIC_RELOC_VANILLA);
+      io.enumCase(value, "GENERIC_RELOC_PAIR",
+                                  llvm::MachO::GENERIC_RELOC_PAIR);
+      io.enumCase(value, "GENERIC_RELOC_SECTDIFF",
+                                  llvm::MachO::GENERIC_RELOC_SECTDIFF);
+      io.enumCase(value, "GENERIC_RELOC_LOCAL_SECTDIFF",
+                                  llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+      io.enumCase(value, "GENERIC_RELOC_TLV",
+                                  llvm::MachO::GENERIC_RELOC_TLV);
+      break;
+    case lld::MachOLinkingContext::arch_armv6:
+    case lld::MachOLinkingContext::arch_armv7:
+    case lld::MachOLinkingContext::arch_armv7s:
+       io.enumCase(value, "ARM_RELOC_VANILLA",
+                                  llvm::MachO::ARM_RELOC_VANILLA);
+      io.enumCase(value, "ARM_RELOC_PAIR",
+                                  llvm::MachO::ARM_RELOC_PAIR);
+      io.enumCase(value, "ARM_RELOC_SECTDIFF",
+                                  llvm::MachO::ARM_RELOC_SECTDIFF);
+      io.enumCase(value, "ARM_RELOC_LOCAL_SECTDIFF",
+                                  llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF);
+      io.enumCase(value, "ARM_RELOC_BR24",
+                                  llvm::MachO::ARM_RELOC_BR24);
+      io.enumCase(value, "ARM_THUMB_RELOC_BR22",
+                                  llvm::MachO::ARM_THUMB_RELOC_BR22);
+      io.enumCase(value, "ARM_RELOC_HALF",
+                                  llvm::MachO::ARM_RELOC_HALF);
+      io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",
+                                  llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+      break;
+    case lld::MachOLinkingContext::arch_arm64:
+      io.enumCase(value, "ARM64_RELOC_UNSIGNED",
+                                  llvm::MachO::ARM64_RELOC_UNSIGNED);
+      io.enumCase(value, "ARM64_RELOC_SUBTRACTOR",
+                                  llvm::MachO::ARM64_RELOC_SUBTRACTOR);
+      io.enumCase(value, "ARM64_RELOC_BRANCH26",
+                                  llvm::MachO::ARM64_RELOC_BRANCH26);
+      io.enumCase(value, "ARM64_RELOC_PAGE21",
+                                  llvm::MachO::ARM64_RELOC_PAGE21);
+      io.enumCase(value, "ARM64_RELOC_PAGEOFF12",
+                                  llvm::MachO::ARM64_RELOC_PAGEOFF12);
+      io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGE21",
+                                  llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
+      io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
+                                  llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
+      io.enumCase(value, "ARM64_RELOC_POINTER_TO_GOT",
+                                  llvm::MachO::ARM64_RELOC_POINTER_TO_GOT);
+      io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGE21",
+                                  llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
+      io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
+                                  llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
+      io.enumCase(value, "ARM64_RELOC_ADDEND",
+                                  llvm::MachO::ARM64_RELOC_ADDEND);
+      break;
+    default:
+      llvm_unreachable("unknown architecture");
+    }
+ }
+};
+
+
+template <>
+struct MappingTraits<Symbol> {
+  static void mapping(IO &io, Symbol& sym) {
+    io.mapRequired("name",    sym.name);
+    io.mapRequired("type",    sym.type);
+    io.mapOptional("scope",   sym.scope, SymbolScope(0));
+    io.mapOptional("sect",    sym.sect, (uint8_t)0);
+    if (sym.type == llvm::MachO::N_UNDF) {
+      // In undef symbols, desc field contains alignment/ordinal info
+      // which is better represented as a hex vaule.
+      uint16_t t1 = sym.desc;
+      Hex16 t2 = t1;
+      io.mapOptional("desc",  t2, Hex16(0));
+      sym.desc = t2;
+    } else {
+      // In defined symbols, desc fit is a set of option bits.
+      io.mapOptional("desc",    sym.desc, SymbolDesc(0));
+    }
+    io.mapRequired("value",  sym.value);
+  }
+};
+
+// Custom mapping for VMProtect (e.g. "r-x").
+template <>
+struct ScalarTraits<VMProtect> {
+  static void output(const VMProtect &value, void*, raw_ostream &out) {
+    out << ( (value & llvm::MachO::VM_PROT_READ)    ? 'r' : '-');
+    out << ( (value & llvm::MachO::VM_PROT_WRITE)   ? 'w' : '-');
+    out << ( (value & llvm::MachO::VM_PROT_EXECUTE) ? 'x' : '-');
+  }
+  static StringRef input(StringRef scalar, void*, VMProtect &value) {
+    value = 0;
+    if (scalar.size() != 3)
+      return "segment access protection must be three chars (e.g. \"r-x\")";
+    switch (scalar[0]) {
+    case 'r':
+      value = llvm::MachO::VM_PROT_READ;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection first char must be 'r' or '-'";
+    }
+    switch (scalar[1]) {
+    case 'w':
+      value = value | llvm::MachO::VM_PROT_WRITE;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection second char must be 'w' or '-'";
+    }
+    switch (scalar[2]) {
+    case 'x':
+      value = value | llvm::MachO::VM_PROT_EXECUTE;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection third char must be 'x' or '-'";
+    }
+    // Return the empty string on success,
+    return StringRef();
+  }
+  static bool mustQuote(StringRef) { return false; }
+};
+
+
+template <>
+struct MappingTraits<Segment> {
+  static void mapping(IO &io, Segment& seg) {
+    io.mapRequired("name",            seg.name);
+    io.mapRequired("address",         seg.address);
+    io.mapRequired("size",            seg.size);
+    io.mapRequired("init-access",     seg.init_access);
+    io.mapRequired("max-access",      seg.max_access);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<LoadCommandType> {
+  static void enumeration(IO &io, LoadCommandType &value) {
+    io.enumCase(value, "LC_LOAD_DYLIB",
+                        llvm::MachO::LC_LOAD_DYLIB);
+    io.enumCase(value, "LC_LOAD_WEAK_DYLIB",
+                        llvm::MachO::LC_LOAD_WEAK_DYLIB);
+    io.enumCase(value, "LC_REEXPORT_DYLIB",
+                        llvm::MachO::LC_REEXPORT_DYLIB);
+    io.enumCase(value, "LC_LOAD_UPWARD_DYLIB",
+                        llvm::MachO::LC_LOAD_UPWARD_DYLIB);
+    io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
+                        llvm::MachO::LC_LAZY_LOAD_DYLIB);
+    io.enumCase(value, "LC_VERSION_MIN_MACOSX",
+                        llvm::MachO::LC_VERSION_MIN_MACOSX);
+    io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
+                        llvm::MachO::LC_VERSION_MIN_IPHONEOS);
+    io.enumCase(value, "LC_VERSION_MIN_TVOS",
+                        llvm::MachO::LC_VERSION_MIN_TVOS);
+    io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
+                        llvm::MachO::LC_VERSION_MIN_WATCHOS);
+  }
+};
+
+template <>
+struct MappingTraits<DependentDylib> {
+  static void mapping(IO &io, DependentDylib& dylib) {
+    io.mapRequired("path",            dylib.path);
+    io.mapOptional("kind",            dylib.kind,
+                                      llvm::MachO::LC_LOAD_DYLIB);
+    io.mapOptional("compat-version",  dylib.compatVersion,
+                                      PackedVersion(0x10000));
+    io.mapOptional("current-version", dylib.currentVersion,
+                                      PackedVersion(0x10000));
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<RebaseType> {
+  static void enumeration(IO &io, RebaseType &value) {
+    io.enumCase(value, "REBASE_TYPE_POINTER",
+                        llvm::MachO::REBASE_TYPE_POINTER);
+    io.enumCase(value, "REBASE_TYPE_TEXT_PCREL32",
+                        llvm::MachO::REBASE_TYPE_TEXT_PCREL32);
+    io.enumCase(value, "REBASE_TYPE_TEXT_ABSOLUTE32",
+                        llvm::MachO::REBASE_TYPE_TEXT_ABSOLUTE32);
+  }
+};
+
+
+template <>
+struct MappingTraits<RebaseLocation> {
+  static void mapping(IO &io, RebaseLocation& rebase) {
+    io.mapRequired("segment-index",   rebase.segIndex);
+    io.mapRequired("segment-offset",  rebase.segOffset);
+    io.mapOptional("kind",            rebase.kind,
+                                      llvm::MachO::REBASE_TYPE_POINTER);
+  }
+};
+
+
+
+template <>
+struct ScalarEnumerationTraits<BindType> {
+  static void enumeration(IO &io, BindType &value) {
+    io.enumCase(value, "BIND_TYPE_POINTER",
+                        llvm::MachO::BIND_TYPE_POINTER);
+    io.enumCase(value, "BIND_TYPE_TEXT_ABSOLUTE32",
+                        llvm::MachO::BIND_TYPE_TEXT_ABSOLUTE32);
+    io.enumCase(value, "BIND_TYPE_TEXT_PCREL32",
+                        llvm::MachO::BIND_TYPE_TEXT_PCREL32);
+  }
+};
+
+template <>
+struct MappingTraits<BindLocation> {
+  static void mapping(IO &io, BindLocation &bind) {
+    io.mapRequired("segment-index",   bind.segIndex);
+    io.mapRequired("segment-offset",  bind.segOffset);
+    io.mapOptional("kind",            bind.kind,
+                                      llvm::MachO::BIND_TYPE_POINTER);
+    io.mapOptional("can-be-null",     bind.canBeNull, false);
+    io.mapRequired("ordinal",         bind.ordinal);
+    io.mapRequired("symbol-name",     bind.symbolName);
+    io.mapOptional("addend",          bind.addend, Hex64(0));
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<ExportSymbolKind> {
+  static void enumeration(IO &io, ExportSymbolKind &value) {
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL",
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE",
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<ExportFlags> {
+  static void bitset(IO &io, ExportFlags &value) {
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION",
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_REEXPORT",
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER",
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+  }
+};
+
+
+template <>
+struct MappingTraits<Export> {
+  static void mapping(IO &io, Export &exp) {
+    io.mapRequired("name",         exp.name);
+    io.mapOptional("offset",       exp.offset);
+    io.mapOptional("kind",         exp.kind,
+                                llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+    if (!io.outputting() || exp.flags)
+      io.mapOptional("flags",      exp.flags);
+    io.mapOptional("other",        exp.otherOffset, Hex32(0));
+    io.mapOptional("other-name",   exp.otherName, StringRef());
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<DataRegionType> {
+  static void enumeration(IO &io, DataRegionType &value) {
+    io.enumCase(value, "DICE_KIND_DATA",
+                        llvm::MachO::DICE_KIND_DATA);
+    io.enumCase(value, "DICE_KIND_JUMP_TABLE8",
+                        llvm::MachO::DICE_KIND_JUMP_TABLE8);
+    io.enumCase(value, "DICE_KIND_JUMP_TABLE16",
+                        llvm::MachO::DICE_KIND_JUMP_TABLE16);
+    io.enumCase(value, "DICE_KIND_JUMP_TABLE32",
+                        llvm::MachO::DICE_KIND_JUMP_TABLE32);
+    io.enumCase(value, "DICE_KIND_ABS_JUMP_TABLE32",
+                        llvm::MachO::DICE_KIND_ABS_JUMP_TABLE32);
+  }
+};
+
+template <>
+struct MappingTraits<DataInCode> {
+  static void mapping(IO &io, DataInCode &entry) {
+    io.mapRequired("offset",       entry.offset);
+    io.mapRequired("length",       entry.length);
+    io.mapRequired("kind",         entry.kind);
+  }
+};
+
+template <>
+struct ScalarTraits<PackedVersion> {
+  static void output(const PackedVersion &value, void*, raw_ostream &out) {
+    out << llvm::format("%d.%d", (value >> 16), (value >> 8) & 0xFF);
+    if (value & 0xFF) {
+      out << llvm::format(".%d", (value & 0xFF));
+    }
+  }
+  static StringRef input(StringRef scalar, void*, PackedVersion &result) {
+    uint32_t value;
+    if (lld::MachOLinkingContext::parsePackedVersion(scalar, value))
+      return "malformed version number";
+    result = value;
+    // Return the empty string on success,
+    return StringRef();
+  }
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <>
+struct MappingTraits<NormalizedFile> {
+  static void mapping(IO &io, NormalizedFile &file) {
+    io.mapRequired("arch",             file.arch);
+    io.mapRequired("file-type",        file.fileType);
+    io.mapOptional("flags",            file.flags);
+    io.mapOptional("dependents",       file.dependentDylibs);
+    io.mapOptional("install-name",     file.installName,    StringRef());
+    io.mapOptional("compat-version",   file.compatVersion,  PackedVersion(0x10000));
+    io.mapOptional("current-version",  file.currentVersion, PackedVersion(0x10000));
+    io.mapOptional("has-UUID",         file.hasUUID,        true);
+    io.mapOptional("rpaths",           file.rpaths);
+    io.mapOptional("entry-point",      file.entryAddress,   Hex64(0));
+    io.mapOptional("stack-size",       file.stackSize,      Hex64(0));
+    io.mapOptional("source-version",   file.sourceVersion,  Hex64(0));
+    io.mapOptional("OS",               file.os);
+    io.mapOptional("min-os-version",   file.minOSverson,    PackedVersion(0));
+    io.mapOptional("min-os-version-kind",   file.minOSVersionKind, (LoadCommandType)0);
+    io.mapOptional("sdk-version",      file.sdkVersion,     PackedVersion(0));
+    io.mapOptional("segments",         file.segments);
+    io.mapOptional("sections",         file.sections);
+    io.mapOptional("local-symbols",    file.localSymbols);
+    io.mapOptional("global-symbols",   file.globalSymbols);
+    io.mapOptional("undefined-symbols",file.undefinedSymbols);
+    io.mapOptional("page-size",        file.pageSize,       Hex32(4096));
+    io.mapOptional("rebasings",        file.rebasingInfo);
+    io.mapOptional("bindings",         file.bindingInfo);
+    io.mapOptional("weak-bindings",    file.weakBindingInfo);
+    io.mapOptional("lazy-bindings",    file.lazyBindingInfo);
+    io.mapOptional("exports",          file.exportInfo);
+    io.mapOptional("dataInCode",       file.dataInCode);
+  }
+  static StringRef validate(IO &io, NormalizedFile &file) {
+    return StringRef();
+  }
+};
+
+} // namespace llvm
+} // namespace yaml
+
+
+namespace lld {
+namespace mach_o {
+
+/// Handles !mach-o tagged yaml documents.
+bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
+                                                 const lld::File *&file) const {
+  if (!io.mapTag("!mach-o"))
+    return false;
+  // Step 1: parse yaml into normalized mach-o struct.
+  NormalizedFile nf;
+  YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+  assert(info != nullptr);
+  assert(info->_normalizeMachOFile == nullptr);
+  info->_normalizeMachOFile = &nf;
+  MappingTraits<NormalizedFile>::mapping(io, nf);
+  // Step 2: parse normalized mach-o struct into atoms.
+  auto fileOrError = normalizedToAtoms(nf, info->_path, true);
+
+  // Check that we parsed successfully.
+  if (!fileOrError) {
+    std::string buffer;
+    llvm::raw_string_ostream stream(buffer);
+    handleAllErrors(fileOrError.takeError(),
+                    [&](const llvm::ErrorInfoBase &EI) {
+      EI.log(stream);
+      stream << "\n";
+    });
+    io.setError(stream.str());
+    return false;
+  }
+
+  if (nf.arch != _arch) {
+    io.setError(Twine("file is wrong architecture. Expected ("
+                      + MachOLinkingContext::nameFromArch(_arch)
+                      + ") found ("
+                      + MachOLinkingContext::nameFromArch(nf.arch)
+                      + ")"));
+    return false;
+  }
+  info->_normalizeMachOFile = nullptr;
+  file = fileOrError->release();
+  return true;
+}
+
+
+
+namespace normalized {
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readYaml(std::unique_ptr<MemoryBuffer> &mb) {
+  // Make empty NormalizedFile.
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+  // Create YAML Input parser.
+  YamlContext yamlContext;
+  yamlContext._normalizeMachOFile = f.get();
+  llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
+
+  // Fill NormalizedFile by parsing yaml.
+  yin >> *f;
+
+  // Return error if there were parsing problems.
+  if (auto ec = yin.error())
+    return llvm::make_error<GenericError>(Twine("YAML parsing error: ")
+                                          + ec.message());
+
+  // Hand ownership of instantiated NormalizedFile to caller.
+  return std::move(f);
+}
+
+
+/// Writes a yaml encoded mach-o files from an in-memory normalized view.
+std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out) {
+  // YAML I/O is not const aware, so need to cast away ;-(
+  NormalizedFile *f = const_cast<NormalizedFile*>(&file);
+
+  // Create yaml Output writer, using yaml options for context.
+  YamlContext yamlContext;
+  yamlContext._normalizeMachOFile = f;
+  llvm::yaml::Output yout(out, &yamlContext);
+
+  // Stream out yaml.
+  yout << *f;
+
+  return std::error_code();
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachOPasses.h b/lib/ReaderWriter/MachO/MachOPasses.h
new file mode 100644 (file)
index 0000000..cd01d4a
--- /dev/null
@@ -0,0 +1,30 @@
+//===- lib/ReaderWriter/MachO/MachOPasses.h -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_PASSES_H
+#define LLD_READER_WRITER_MACHO_PASSES_H
+
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addShimPass(PassManager &pm, const MachOLinkingContext &ctx);
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_PASSES_H
diff --git a/lib/ReaderWriter/MachO/ObjCPass.cpp b/lib/ReaderWriter/MachO/ObjCPass.cpp
new file mode 100644 (file)
index 0000000..ccea081
--- /dev/null
@@ -0,0 +1,132 @@
+//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// ObjC Image Info Atom created by the ObjC pass.
+///
+class ObjCImageInfoAtom : public SimpleDefinedAtom {
+public:
+  ObjCImageInfoAtom(const File &file, bool isBig,
+                    MachOLinkingContext::ObjCConstraint objCConstraint,
+                    uint32_t swiftVersion)
+      : SimpleDefinedAtom(file) {
+
+    Data.info.version = 0;
+
+    switch (objCConstraint) {
+    case MachOLinkingContext::objc_unknown:
+      llvm_unreachable("Shouldn't run the objc pass without a constraint");
+    case MachOLinkingContext::objc_supports_gc:
+    case MachOLinkingContext::objc_gc_only:
+      llvm_unreachable("GC is not supported");
+    case MachOLinkingContext::objc_retainReleaseForSimulator:
+      // The retain/release for simulator flag is already the correct
+      // encoded value for the data so just set it here.
+      Data.info.flags = (uint32_t)objCConstraint;
+      break;
+    case MachOLinkingContext::objc_retainRelease:
+      // We don't need to encode this flag, so just leave the flags as 0.
+      Data.info.flags = 0;
+      break;
+    }
+
+    Data.info.flags |= (swiftVersion << 8);
+
+    normalized::write32(Data.bytes + 4, Data.info.flags, isBig);
+  }
+
+  ~ObjCImageInfoAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeObjCImageInfo;
+  }
+
+  Alignment alignment() const override {
+    return 4;
+  }
+
+  uint64_t size() const override {
+    return 8;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR__;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(Data.bytes, size());
+  }
+
+private:
+
+  struct objc_image_info  {
+    uint32_t   version;
+    uint32_t   flags;
+  };
+
+  union {
+    objc_image_info info;
+    uint8_t bytes[8];
+  } Data;
+};
+
+class ObjCPass : public Pass {
+public:
+  ObjCPass(const MachOLinkingContext &context)
+      : _ctx(context),
+        _file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Add the image info.
+    mergedFile.addAtom(*getImageInfo());
+
+    return llvm::Error::success();
+  }
+
+private:
+
+  const DefinedAtom* getImageInfo() {
+    bool IsBig = MachOLinkingContext::isBigEndian(_ctx.arch());
+    return new (_file.allocator()) ObjCImageInfoAtom(_file, IsBig,
+                                                     _ctx.objcConstraint(),
+                                                     _ctx.swiftVersion());
+  }
+
+  const MachOLinkingContext   &_ctx;
+  MachOFile                   &_file;
+};
+
+
+
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(llvm::make_unique<ObjCPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/SectCreateFile.h b/lib/ReaderWriter/MachO/SectCreateFile.h
new file mode 100644 (file)
index 0000000..49e65f6
--- /dev/null
@@ -0,0 +1,102 @@
+//===---- lib/ReaderWriter/MachO/SectCreateFile.h ---------------*- c++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
+#define LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class SectCreateFile : public File {
+public:
+  class SectCreateAtom : public SimpleDefinedAtom {
+  public:
+    SectCreateAtom(const File &file, StringRef segName, StringRef sectName,
+                   std::unique_ptr<MemoryBuffer> content)
+      : SimpleDefinedAtom(file),
+        _combinedName((segName + "/" + sectName).str()),
+        _content(std::move(content)) {}
+
+    ~SectCreateAtom() override = default;
+
+    uint64_t size() const override { return _content->getBufferSize(); }
+
+    Scope scope() const override { return scopeGlobal; }
+
+    ContentType contentType() const override { return typeSectCreate; }
+
+    SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+    StringRef customSectionName() const override { return _combinedName; }
+
+    DeadStripKind deadStrip() const override { return deadStripNever; }
+
+    ArrayRef<uint8_t> rawContent() const override {
+      const uint8_t *data =
+        reinterpret_cast<const uint8_t*>(_content->getBufferStart());
+      return ArrayRef<uint8_t>(data, _content->getBufferSize());
+    }
+
+    StringRef segmentName() const { return _segName; }
+    StringRef sectionName() const { return _sectName; }
+
+  private:
+    std::string _combinedName;
+    StringRef _segName;
+    StringRef _sectName;
+    std::unique_ptr<MemoryBuffer> _content;
+  };
+
+  SectCreateFile() : File("sectcreate", kindSectCreateObject) {}
+
+  void addSection(StringRef seg, StringRef sect,
+                  std::unique_ptr<MemoryBuffer> content) {
+    _definedAtoms.push_back(
+      new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content)));
+  }
+
+  const AtomRange<DefinedAtom> defined() const override {
+    return _definedAtoms;
+  }
+
+  const AtomRange<UndefinedAtom> undefined() const override {
+    return _noUndefinedAtoms;
+  }
+
+  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+    return _noSharedLibraryAtoms;
+  }
+
+  const AtomRange<AbsoluteAtom> absolute() const override {
+    return _noAbsoluteAtoms;
+  }
+
+  void clearAtoms() override {
+    _definedAtoms.clear();
+    _noUndefinedAtoms.clear();
+    _noSharedLibraryAtoms.clear();
+    _noAbsoluteAtoms.clear();
+  }
+
+private:
+  AtomVector<DefinedAtom> _definedAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp
new file mode 100644 (file)
index 0000000..ff559d7
--- /dev/null
@@ -0,0 +1,129 @@
+//===- lib/ReaderWriter/MachO/ShimPass.cpp -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This linker pass updates branch-sites whose target is a different mode
+// (thumb vs arm).
+//
+// Arm code has two instruction encodings thumb and arm.  When branching from
+// one code encoding to another, you need to use an instruction that switches
+// the instruction mode.  Usually the transition only happens at call sites, and
+// the linker can transform a BL instruction in BLX (or vice versa).  But if the
+// compiler did a tail call optimization and a function ends with a branch (not
+// branch and link), there is no pc-rel BX instruction.
+//
+// The ShimPass looks for pc-rel B instructions that will need to switch mode.
+// For those cases it synthesizes a shim which does the transition, then
+// modifies the original atom with the B instruction to target to the shim atom.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+class ShimPass : public Pass {
+public:
+  ShimPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _stubInfo(_archHandler.stubInfo()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o shim pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at non-call branches.
+        if (!_archHandler.isNonCallBranch(*ref))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+        if (const lld::DefinedAtom *daTarget = dyn_cast<DefinedAtom>(target)) {
+          bool atomIsThumb = _archHandler.isThumbFunction(*atom);
+          bool targetIsThumb = _archHandler.isThumbFunction(*daTarget);
+          if (atomIsThumb != targetIsThumb)
+            updateBranchToUseShim(atomIsThumb, *daTarget, ref);
+        }
+      }
+    }
+    // Exit early if no shims needed.
+    if (_targetToShim.empty())
+      return llvm::Error::success();
+
+    // Sort shim atoms so the layout order is stable.
+    std::vector<const DefinedAtom *> shims;
+    shims.reserve(_targetToShim.size());
+    for (auto element : _targetToShim) {
+      shims.push_back(element.second);
+    }
+    std::sort(shims.begin(), shims.end(),
+              [](const DefinedAtom *l, const DefinedAtom *r) {
+                return (l->name() < r->name());
+              });
+
+    // Add all shims to master file.
+    for (const DefinedAtom *shim : shims)
+      mergedFile.addAtom(*shim);
+
+    return llvm::Error::success();
+  }
+
+private:
+
+  void updateBranchToUseShim(bool thumbToArm, const DefinedAtom& target,
+                             const Reference *ref) {
+    // Make file-format specific stub and other support atoms.
+    const DefinedAtom *shim = this->getShim(thumbToArm, target);
+    assert(shim != nullptr);
+    // Switch branch site to target shim atom.
+    const_cast<Reference *>(ref)->setTarget(shim);
+  }
+
+  const DefinedAtom* getShim(bool thumbToArm, const DefinedAtom& target) {
+    auto pos = _targetToShim.find(&target);
+    if ( pos != _targetToShim.end() ) {
+      // Reuse an existing shim.
+      assert(pos->second != nullptr);
+      return pos->second;
+    } else {
+      // There is no existing shim, so create a new one.
+      const DefinedAtom *shim = _archHandler.createShim(_file, thumbToArm,
+                                                        target);
+       _targetToShim[&target] = shim;
+       return shim;
+    }
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler                            &_archHandler;
+  const ArchHandler::StubInfo                    &_stubInfo;
+  MachOFile                                      &_file;
+  llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToShim;
+};
+
+
+
+void addShimPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(llvm::make_unique<ShimPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp
new file mode 100644 (file)
index 0000000..19e2bc5
--- /dev/null
@@ -0,0 +1,379 @@
+//===- lib/ReaderWriter/MachO/StubsPass.cpp ---------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This linker pass updates call-sites which have references to shared library
+// atoms to instead have a reference to a stub (PLT entry) for the specified
+// symbol.  Each file format defines a subclass of StubsPass which implements
+// the abstract methods for creating the file format specific StubAtoms.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+//  Lazy Pointer Atom created by the stubs pass.
+//
+class LazyPointerAtom : public SimpleDefinedAtom {
+public:
+  LazyPointerAtom(const File &file, bool is64)
+    : SimpleDefinedAtom(file), _is64(is64) { }
+
+  ~LazyPointerAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeLazyPointer;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+private:
+  const bool _is64;
+};
+
+//
+//  NonLazyPointer (GOT) Atom created by the stubs pass.
+//
+class NonLazyPointerAtom : public SimpleDefinedAtom {
+public:
+  NonLazyPointerAtom(const File &file, bool is64, ContentType contentType)
+    : SimpleDefinedAtom(file), _is64(is64), _contentType(contentType) { }
+
+  ~NonLazyPointerAtom() override = default;
+
+  ContentType contentType() const override {
+    return _contentType;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+private:
+  const bool _is64;
+  const ContentType _contentType;
+};
+
+//
+// Stub Atom created by the stubs pass.
+//
+class StubAtom : public SimpleDefinedAtom {
+public:
+  StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo){ }
+
+  ~StubAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStub;
+  }
+
+  Alignment alignment() const override {
+    return 1 << _stubInfo.codeAlignment;
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubBytes, _stubInfo.stubSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+//
+// Stub Helper Atom created by the stubs pass.
+//
+class StubHelperAtom : public SimpleDefinedAtom {
+public:
+  StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+  ~StubHelperAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStubHelper;
+  }
+
+  Alignment alignment() const override {
+    return 1 << _stubInfo.codeAlignment;
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubHelperSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubHelperBytes,
+                              _stubInfo.stubHelperSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+//
+// Stub Helper Common Atom created by the stubs pass.
+//
+class StubHelperCommonAtom : public SimpleDefinedAtom {
+public:
+  StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+  ~StubHelperCommonAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStubHelper;
+  }
+
+  Alignment alignment() const override {
+    return 1 << _stubInfo.stubHelperCommonAlignment;
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubHelperCommonSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubHelperCommonBytes,
+                        _stubInfo.stubHelperCommonSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+class StubsPass : public Pass {
+public:
+  StubsPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _stubInfo(_archHandler.stubInfo()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o Stubs pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    // Skip this pass if output format uses text relocations instead of stubs.
+    if (!this->noTextRelocs())
+      return llvm::Error::success();
+
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at call-sites.
+        if (!this->isCallSite(*ref))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+        if (isa<SharedLibraryAtom>(target)) {
+          // Calls to shared libraries go through stubs.
+          _targetToUses[target].push_back(ref);
+          continue;
+        }
+        const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+        if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){
+          // Calls to interposable functions in same linkage unit must also go
+          // through a stub.
+          assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+          _targetToUses[target].push_back(ref);
+        }
+      }
+    }
+
+    // Exit early if no stubs needed.
+    if (_targetToUses.empty())
+      return llvm::Error::success();
+
+    // First add help-common and GOT slots used by lazy binding.
+    SimpleDefinedAtom *helperCommonAtom =
+        new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo);
+    SimpleDefinedAtom *helperCacheNLPAtom =
+        new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+                                    _stubInfo.stubHelperImageCacheContentType);
+    SimpleDefinedAtom *helperBinderNLPAtom =
+        new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+                                    _stubInfo.stubHelperImageCacheContentType);
+    addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
+                 helperCacheNLPAtom);
+    addOptReference(
+        helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
+        _stubInfo.optStubHelperCommonReferenceToCache, helperCacheNLPAtom);
+    addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder,
+                 helperBinderNLPAtom);
+    addOptReference(
+        helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder,
+        _stubInfo.optStubHelperCommonReferenceToBinder, helperBinderNLPAtom);
+    mergedFile.addAtom(*helperCommonAtom);
+    mergedFile.addAtom(*helperBinderNLPAtom);
+    mergedFile.addAtom(*helperCacheNLPAtom);
+
+    // Add reference to dyld_stub_binder in libSystem.dylib
+    auto I = std::find_if(
+        mergedFile.sharedLibrary().begin(), mergedFile.sharedLibrary().end(),
+        [&](const SharedLibraryAtom *atom) {
+          return atom->name().equals(_stubInfo.binderSymbolName);
+        });
+    assert(I != mergedFile.sharedLibrary().end() &&
+           "dyld_stub_binder not found");
+    addReference(helperBinderNLPAtom, _stubInfo.nonLazyPointerReferenceToBinder, *I);
+
+    // Sort targets by name, so stubs and lazy pointers are consistent
+    std::vector<const Atom *> targetsNeedingStubs;
+    for (auto it : _targetToUses)
+      targetsNeedingStubs.push_back(it.first);
+    std::sort(targetsNeedingStubs.begin(), targetsNeedingStubs.end(),
+              [](const Atom * left, const Atom * right) {
+      return (left->name().compare(right->name()) < 0);
+    });
+
+    // Make and append stubs, lazy pointers, and helpers in alphabetical order.
+    unsigned lazyOffset = 0;
+    for (const Atom *target : targetsNeedingStubs) {
+      auto *stub = new (_file.allocator()) StubAtom(_file, _stubInfo);
+      auto *lp =
+          new (_file.allocator()) LazyPointerAtom(_file, _ctx.is64Bit());
+      auto *helper = new (_file.allocator()) StubHelperAtom(_file, _stubInfo);
+
+      addReference(stub, _stubInfo.stubReferenceToLP, lp);
+      addOptReference(stub, _stubInfo.stubReferenceToLP,
+                      _stubInfo.optStubReferenceToLP, lp);
+      addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper);
+      addReference(lp, _stubInfo.lazyPointerReferenceToFinal, target);
+      addReference(helper, _stubInfo.stubHelperReferenceToImm, helper);
+      addReferenceAddend(helper, _stubInfo.stubHelperReferenceToImm, helper,
+                         lazyOffset);
+      addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon,
+                   helperCommonAtom);
+
+      mergedFile.addAtom(*stub);
+      mergedFile.addAtom(*lp);
+      mergedFile.addAtom(*helper);
+
+      // Update each reference to use stub.
+      for (const Reference *ref : _targetToUses[target]) {
+        assert(ref->target() == target);
+        // Switch call site to reference stub atom instead.
+        const_cast<Reference *>(ref)->setTarget(stub);
+      }
+
+      // Calculate new offset
+      lazyOffset += target->name().size() + 12;
+    }
+
+    return llvm::Error::success();
+  }
+
+private:
+  bool noTextRelocs() {
+    return true;
+  }
+
+  bool isCallSite(const Reference &ref) {
+    return _archHandler.isCallSite(ref);
+  }
+
+  void addReference(SimpleDefinedAtom* atom,
+                    const ArchHandler::ReferenceInfo &refInfo,
+                    const lld::Atom* target) {
+    atom->addReference(Reference::KindNamespace::mach_o,
+                      refInfo.arch, refInfo.kind, refInfo.offset,
+                      target, refInfo.addend);
+  }
+
+  void addReferenceAddend(SimpleDefinedAtom *atom,
+                          const ArchHandler::ReferenceInfo &refInfo,
+                          const lld::Atom *target, uint64_t addend) {
+    atom->addReference(Reference::KindNamespace::mach_o, refInfo.arch,
+                       refInfo.kind, refInfo.offset, target, addend);
+  }
+
+   void addOptReference(SimpleDefinedAtom* atom,
+                    const ArchHandler::ReferenceInfo &refInfo,
+                    const ArchHandler::OptionalRefInfo &optRef,
+                    const lld::Atom* target) {
+      if (!optRef.used)
+        return;
+    atom->addReference(Reference::KindNamespace::mach_o,
+                      refInfo.arch, optRef.kind, optRef.offset,
+                      target, optRef.addend);
+  }
+
+  typedef llvm::DenseMap<const Atom*,
+                         llvm::SmallVector<const Reference *, 8>> TargetToUses;
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler                            &_archHandler;
+  const ArchHandler::StubInfo                    &_stubInfo;
+  MachOFile                                      &_file;
+  TargetToUses                                    _targetToUses;
+};
+
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(std::unique_ptr<Pass>(new StubsPass(ctx)));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/TLVPass.cpp b/lib/ReaderWriter/MachO/TLVPass.cpp
new file mode 100644 (file)
index 0000000..e362e50
--- /dev/null
@@ -0,0 +1,141 @@
+//===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This linker pass transforms all TLV references to real references.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// TLVP Entry Atom created by the TLV pass.
+//
+class TLVPEntryAtom : public SimpleDefinedAtom {
+public:
+  TLVPEntryAtom(const File &file, bool is64, StringRef name)
+      : SimpleDefinedAtom(file), _is64(is64), _name(name) {}
+
+  ~TLVPEntryAtom() override = default;
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeTLVInitializerPtr;
+  }
+
+  Alignment alignment() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+  StringRef slotName() const {
+    return _name;
+  }
+
+private:
+  const bool _is64;
+  StringRef _name;
+};
+
+class TLVPass : public Pass {
+public:
+  TLVPass(const MachOLinkingContext &context)
+      : _ctx(context), _archHandler(_ctx.archHandler()),
+        _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) {
+    _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+  }
+
+private:
+  llvm::Error perform(SimpleFile &mergedFile) override {
+    bool allowTLV = _ctx.minOS("10.7", "1.0");
+
+    for (const DefinedAtom *atom : mergedFile.defined()) {
+      for (const Reference *ref : *atom) {
+        if (!_archHandler.isTLVAccess(*ref))
+          continue;
+
+        if (!allowTLV)
+          return llvm::make_error<GenericError>(
+            "targeted OS version does not support use of thread local "
+            "variables in " + atom->name() + " for architecture " +
+            _ctx.archName());
+
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+
+        const DefinedAtom *tlvpEntry = makeTLVPEntry(target);
+        const_cast<Reference*>(ref)->setTarget(tlvpEntry);
+        _archHandler.updateReferenceToTLV(ref);
+      }
+    }
+
+    std::vector<const TLVPEntryAtom*> entries;
+    entries.reserve(_targetToTLVP.size());
+    for (auto &it : _targetToTLVP)
+      entries.push_back(it.second);
+    std::sort(entries.begin(), entries.end(),
+              [](const TLVPEntryAtom *lhs, const TLVPEntryAtom *rhs) {
+                return (lhs->slotName().compare(rhs->slotName()) < 0);
+              });
+
+    for (const TLVPEntryAtom *slot : entries)
+      mergedFile.addAtom(*slot);
+
+    return llvm::Error::success();
+  }
+
+  const DefinedAtom *makeTLVPEntry(const Atom *target) {
+    auto pos = _targetToTLVP.find(target);
+
+    if (pos != _targetToTLVP.end())
+      return pos->second;
+
+    auto *tlvpEntry = new (_file.allocator())
+      TLVPEntryAtom(_file, _ctx.is64Bit(), target->name());
+    _targetToTLVP[target] = tlvpEntry;
+    const ArchHandler::ReferenceInfo &nlInfo =
+      _archHandler.stubInfo().nonLazyPointerReferenceToBinder;
+    tlvpEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+                            nlInfo.kind, 0, target, 0);
+    return tlvpEntry;
+  }
+
+  const MachOLinkingContext &_ctx;
+  mach_o::ArchHandler &_archHandler;
+  MachOFile           &_file;
+  llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
+};
+
+void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  assert(ctx.needsTLVPass());
+  pm.add(llvm::make_unique<TLVPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp
new file mode 100644 (file)
index 0000000..c457e7b
--- /dev/null
@@ -0,0 +1,71 @@
+//===- lib/ReaderWriter/MachO/WriterMachO.cpp -----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExecutableAtoms.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+using lld::mach_o::normalized::NormalizedFile;
+
+namespace lld {
+namespace mach_o {
+
+class MachOWriter : public Writer {
+public:
+  MachOWriter(const MachOLinkingContext &ctxt) : _ctx(ctxt) {}
+
+  llvm::Error writeFile(const lld::File &file, StringRef path) override {
+    // Construct empty normalized file from atoms.
+    llvm::Expected<std::unique_ptr<NormalizedFile>> nFile =
+        normalized::normalizedFromAtoms(file, _ctx);
+    if (auto ec = nFile.takeError())
+      return ec;
+
+    // For testing, write out yaml form of normalized file.
+    if (_ctx.printAtoms()) {
+      std::unique_ptr<Writer> yamlWriter = createWriterYAML(_ctx);
+      if (auto ec = yamlWriter->writeFile(file, "-"))
+        return ec;
+    }
+
+    // Write normalized file as mach-o binary.
+    return writeBinary(*nFile->get(), path);
+  }
+
+  void createImplicitFiles(std::vector<std::unique_ptr<File>> &r) override {
+    // When building main executables, add _main as required entry point.
+    if (_ctx.outputTypeHasEntry())
+      r.emplace_back(new CEntryFile(_ctx));
+    // If this can link with dylibs, need helper function (dyld_stub_binder).
+    if (_ctx.needsStubsPass())
+      r.emplace_back(new StubHelperFile(_ctx));
+    // Final linked images can access a symbol for their mach_header.
+    if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+      r.emplace_back(new MachHeaderAliasFile(_ctx));
+  }
+private:
+  const MachOLinkingContext &_ctx;
+ };
+
+
+} // namespace mach_o
+
+std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &context) {
+  return std::unique_ptr<Writer>(new lld::mach_o::MachOWriter(context));
+}
+
+} // namespace lld
diff --git a/lib/ReaderWriter/YAML/CMakeLists.txt b/lib/ReaderWriter/YAML/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0e63574
--- /dev/null
@@ -0,0 +1,9 @@
+add_lld_library(lldYAML
+  ReaderWriterYAML.cpp
+
+  LINK_COMPONENTS
+    Support
+
+  LINK_LIBS
+    lldCore
+  )
diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
new file mode 100644 (file)
index 0000000..4c88eb1
--- /dev/null
@@ -0,0 +1,1404 @@
+//===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/YamlContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using llvm::file_magic;
+using llvm::yaml::MappingTraits;
+using llvm::yaml::ScalarEnumerationTraits;
+using llvm::yaml::ScalarTraits;
+using llvm::yaml::IO;
+using llvm::yaml::SequenceTraits;
+using llvm::yaml::DocumentListTraits;
+
+using namespace lld;
+
+/// The conversion of Atoms to and from YAML uses LLVM's YAML I/O.  This
+/// file just defines template specializations on the lld types which control
+/// how the mapping is done to and from YAML.
+
+namespace {
+
+/// Used when writing yaml files.
+/// In most cases, atoms names are unambiguous, so references can just
+/// use the atom name as the target (e.g. target: foo).  But in a few
+/// cases that does not work, so ref-names are added.  These are labels
+/// used only in yaml.  The labels do not exist in the Atom model.
+///
+/// One need for ref-names are when atoms have no user supplied name
+/// (e.g. c-string literal).  Another case is when two object files with
+/// identically named static functions are merged (ld -r) into one object file.
+/// In that case referencing the function by name is ambiguous, so a unique
+/// ref-name is added.
+class RefNameBuilder {
+public:
+  RefNameBuilder(const lld::File &file)
+      : _collisionCount(0), _unnamedCounter(0) {
+    // visit all atoms
+    for (const lld::DefinedAtom *atom : file.defined()) {
+      // Build map of atoms names to detect duplicates
+      if (!atom->name().empty())
+        buildDuplicateNameMap(*atom);
+
+      // Find references to unnamed atoms and create ref-names for them.
+      for (const lld::Reference *ref : *atom) {
+        // create refname for any unnamed reference target
+        const lld::Atom *target = ref->target();
+        if ((target != nullptr) && target->name().empty()) {
+          std::string storage;
+          llvm::raw_string_ostream buffer(storage);
+          buffer << llvm::format("L%03d", _unnamedCounter++);
+          StringRef newName = copyString(buffer.str());
+          _refNames[target] = newName;
+          DEBUG_WITH_TYPE("WriterYAML",
+                          llvm::dbgs() << "unnamed atom: creating ref-name: '"
+                                       << newName << "' ("
+                                       << (const void *)newName.data() << ", "
+                                       << newName.size() << ")\n");
+        }
+      }
+    }
+    for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
+      buildDuplicateNameMap(*undefAtom);
+    }
+    for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
+      buildDuplicateNameMap(*shlibAtom);
+    }
+    for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
+      if (!absAtom->name().empty())
+        buildDuplicateNameMap(*absAtom);
+    }
+  }
+
+  void buildDuplicateNameMap(const lld::Atom &atom) {
+    assert(!atom.name().empty());
+    NameToAtom::iterator pos = _nameMap.find(atom.name());
+    if (pos != _nameMap.end()) {
+      // Found name collision, give each a unique ref-name.
+      std::string Storage;
+      llvm::raw_string_ostream buffer(Storage);
+      buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
+      StringRef newName = copyString(buffer.str());
+      _refNames[&atom] = newName;
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "name collsion: creating ref-name: '"
+                                   << newName << "' ("
+                                   << (const void *)newName.data()
+                                   << ", " << newName.size() << ")\n");
+      const lld::Atom *prevAtom = pos->second;
+      AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
+      if (pos2 == _refNames.end()) {
+        // Only create ref-name for previous if none already created.
+        std::string Storage2;
+        llvm::raw_string_ostream buffer2(Storage2);
+        buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
+        StringRef newName2 = copyString(buffer2.str());
+        _refNames[prevAtom] = newName2;
+        DEBUG_WITH_TYPE("WriterYAML",
+                        llvm::dbgs() << "name collsion: creating ref-name: '"
+                                     << newName2 << "' ("
+                                     << (const void *)newName2.data() << ", "
+                                     << newName2.size() << ")\n");
+      }
+    } else {
+      // First time we've seen this name, just add it to map.
+      _nameMap[atom.name()] = &atom;
+      DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+                                        << "atom name seen for first time: '"
+                                        << atom.name() << "' ("
+                                        << (const void *)atom.name().data()
+                                        << ", " << atom.name().size() << ")\n");
+    }
+  }
+
+  bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
+
+  StringRef refName(const lld::Atom *atom) {
+    return _refNames.find(atom)->second;
+  }
+
+private:
+  typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+  typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName;
+
+  // Allocate a new copy of this string in _storage, so the strings
+  // can be freed when RefNameBuilder is destroyed.
+  StringRef copyString(StringRef str) {
+    char *s = _storage.Allocate<char>(str.size());
+    memcpy(s, str.data(), str.size());
+    return StringRef(s, str.size());
+  }
+
+  unsigned int                         _collisionCount;
+  unsigned int                         _unnamedCounter;
+  NameToAtom                           _nameMap;
+  AtomToRefName                        _refNames;
+  llvm::BumpPtrAllocator               _storage;
+};
+
+/// Used when reading yaml files to find the target of a reference
+/// that could be a name or ref-name.
+class RefNameResolver {
+public:
+  RefNameResolver(const lld::File *file, IO &io);
+
+  const lld::Atom *lookup(StringRef name) const {
+    NameToAtom::const_iterator pos = _nameMap.find(name);
+    if (pos != _nameMap.end())
+      return pos->second;
+    _io.setError(Twine("no such atom name: ") + name);
+    return nullptr;
+  }
+
+private:
+  typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+  void add(StringRef name, const lld::Atom *atom) {
+    if (_nameMap.count(name)) {
+      _io.setError(Twine("duplicate atom name: ") + name);
+    } else {
+      _nameMap[name] = atom;
+    }
+  }
+
+  IO &_io;
+  NameToAtom _nameMap;
+};
+
+/// Mapping of Atoms.
+template <typename T> class AtomList {
+  using Ty = std::vector<OwningAtomPtr<T>>;
+
+public:
+  typename Ty::iterator begin() { return _atoms.begin(); }
+  typename Ty::iterator end() { return _atoms.end(); }
+  Ty _atoms;
+};
+
+/// Mapping of kind: field in yaml files.
+enum FileKinds {
+  fileKindObjectAtoms, // atom based object file encoded in yaml
+  fileKindArchive,     // static archive library encoded in yaml
+  fileKindObjectMachO  // mach-o object files encoded in yaml
+};
+
+struct ArchMember {
+  FileKinds         _kind;
+  StringRef         _name;
+  const lld::File  *_content;
+};
+
+// The content bytes in a DefinedAtom are just uint8_t but we want
+// special formatting, so define a strong type.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8)
+
+// SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
+// more readable than just true/false.
+LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull)
+
+// lld::Reference::Kind is a tuple of <namespace, arch, value>.
+// For yaml, we just want one string that encapsulates the tuple.
+struct RefKind {
+  Reference::KindNamespace  ns;
+  Reference::KindArch       arch;
+  Reference::KindValue      value;
+};
+
+} // end anonymous namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
+LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
+// Always write DefinedAtoms content bytes as a flow sequence.
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8)
+
+// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
+namespace llvm {
+namespace yaml {
+
+// This is a custom formatter for RefKind
+template <> struct ScalarTraits<RefKind> {
+  static void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
+    assert(ctxt != nullptr);
+    YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
+    assert(info->_registry);
+    StringRef str;
+    if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
+                                               str))
+      out << str;
+    else
+      out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
+  }
+
+  static StringRef input(StringRef scalar, void *ctxt, RefKind &kind) {
+    assert(ctxt != nullptr);
+    YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
+    assert(info->_registry);
+    if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch,
+                                                 kind.value))
+      return StringRef();
+    return StringRef("unknown reference kind");
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <> struct ScalarEnumerationTraits<lld::File::Kind> {
+  static void enumeration(IO &io, lld::File::Kind &value) {
+    io.enumCase(value, "error-object",   lld::File::kindErrorObject);
+    io.enumCase(value, "object",         lld::File::kindMachObject);
+    io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
+    io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::Atom::Scope> {
+  static void enumeration(IO &io, lld::Atom::Scope &value) {
+    io.enumCase(value, "global", lld::Atom::scopeGlobal);
+    io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
+    io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
+  static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
+    io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
+    io.enumCase(value, "custom",  lld::DefinedAtom::sectionCustomPreferred);
+    io.enumCase(value, "custom-required",
+                                 lld::DefinedAtom::sectionCustomRequired);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
+  static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
+    io.enumCase(value, "no",           DefinedAtom::interposeNo);
+    io.enumCase(value, "yes",          DefinedAtom::interposeYes);
+    io.enumCase(value, "yes-and-weak", DefinedAtom::interposeYesAndRuntimeWeak);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
+  static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
+    io.enumCase(value, "no",           lld::DefinedAtom::mergeNo);
+    io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
+    io.enumCase(value, "as-weak",      lld::DefinedAtom::mergeAsWeak);
+    io.enumCase(value, "as-addressed-weak",
+                                   lld::DefinedAtom::mergeAsWeakAndAddressUsed);
+    io.enumCase(value, "by-content",   lld::DefinedAtom::mergeByContent);
+    io.enumCase(value, "same-name-and-size",
+                lld::DefinedAtom::mergeSameNameAndSize);
+    io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
+  static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
+    io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
+    io.enumCase(value, "never",  lld::DefinedAtom::deadStripNever);
+    io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DynamicExport> {
+  static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
+    io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
+    io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
+  static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
+    io.enumCase(value, "none", lld::DefinedAtom::codeNA);
+    io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
+    io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
+    io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
+    io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
+    io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
+    io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
+    io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
+    io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
+  static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
+    io.enumCase(value, "---",     lld::DefinedAtom::perm___);
+    io.enumCase(value, "r--",     lld::DefinedAtom::permR__);
+    io.enumCase(value, "r-x",     lld::DefinedAtom::permR_X);
+    io.enumCase(value, "rw-",     lld::DefinedAtom::permRW_);
+    io.enumCase(value, "rwx",     lld::DefinedAtom::permRWX);
+    io.enumCase(value, "rw-l",    lld::DefinedAtom::permRW_L);
+    io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
+  static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
+    io.enumCase(value, "unknown",         DefinedAtom::typeUnknown);
+    io.enumCase(value, "code",            DefinedAtom::typeCode);
+    io.enumCase(value, "stub",            DefinedAtom::typeStub);
+    io.enumCase(value, "constant",        DefinedAtom::typeConstant);
+    io.enumCase(value, "data",            DefinedAtom::typeData);
+    io.enumCase(value, "quick-data",      DefinedAtom::typeDataFast);
+    io.enumCase(value, "zero-fill",       DefinedAtom::typeZeroFill);
+    io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
+    io.enumCase(value, "const-data",      DefinedAtom::typeConstData);
+    io.enumCase(value, "got",             DefinedAtom::typeGOT);
+    io.enumCase(value, "resolver",        DefinedAtom::typeResolver);
+    io.enumCase(value, "branch-island",   DefinedAtom::typeBranchIsland);
+    io.enumCase(value, "branch-shim",     DefinedAtom::typeBranchShim);
+    io.enumCase(value, "stub-helper",     DefinedAtom::typeStubHelper);
+    io.enumCase(value, "c-string",        DefinedAtom::typeCString);
+    io.enumCase(value, "utf16-string",    DefinedAtom::typeUTF16String);
+    io.enumCase(value, "unwind-cfi",      DefinedAtom::typeCFI);
+    io.enumCase(value, "unwind-lsda",     DefinedAtom::typeLSDA);
+    io.enumCase(value, "const-4-byte",    DefinedAtom::typeLiteral4);
+    io.enumCase(value, "const-8-byte",    DefinedAtom::typeLiteral8);
+    io.enumCase(value, "const-16-byte",   DefinedAtom::typeLiteral16);
+    io.enumCase(value, "lazy-pointer",    DefinedAtom::typeLazyPointer);
+    io.enumCase(value, "lazy-dylib-pointer",
+                                          DefinedAtom::typeLazyDylibPointer);
+    io.enumCase(value, "cfstring",        DefinedAtom::typeCFString);
+    io.enumCase(value, "initializer-pointer",
+                                          DefinedAtom::typeInitializerPtr);
+    io.enumCase(value, "terminator-pointer",
+                                          DefinedAtom::typeTerminatorPtr);
+    io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
+    io.enumCase(value, "objc-class-pointer",
+                                          DefinedAtom::typeObjCClassPtr);
+    io.enumCase(value, "objc-category-list",
+                                          DefinedAtom::typeObjC2CategoryList);
+    io.enumCase(value, "objc-image-info",
+                                          DefinedAtom::typeObjCImageInfo);
+    io.enumCase(value, "objc-method-list",
+                                          DefinedAtom::typeObjCMethodList);
+    io.enumCase(value, "objc-class1",     DefinedAtom::typeObjC1Class);
+    io.enumCase(value, "dtraceDOF",       DefinedAtom::typeDTraceDOF);
+    io.enumCase(value, "interposing-tuples",
+                                          DefinedAtom::typeInterposingTuples);
+    io.enumCase(value, "lto-temp",        DefinedAtom::typeTempLTO);
+    io.enumCase(value, "compact-unwind",  DefinedAtom::typeCompactUnwindInfo);
+    io.enumCase(value, "unwind-info",     DefinedAtom::typeProcessedUnwindInfo);
+    io.enumCase(value, "tlv-thunk",       DefinedAtom::typeThunkTLV);
+    io.enumCase(value, "tlv-data",        DefinedAtom::typeTLVInitialData);
+    io.enumCase(value, "tlv-zero-fill",   DefinedAtom::typeTLVInitialZeroFill);
+    io.enumCase(value, "tlv-initializer-ptr",
+                                          DefinedAtom::typeTLVInitializerPtr);
+    io.enumCase(value, "mach_header",     DefinedAtom::typeMachHeader);
+    io.enumCase(value, "dso_handle",      DefinedAtom::typeDSOHandle);
+    io.enumCase(value, "sectcreate",      DefinedAtom::typeSectCreate);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
+  static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
+    io.enumCase(value, "never",       lld::UndefinedAtom::canBeNullNever);
+    io.enumCase(value, "at-runtime",  lld::UndefinedAtom::canBeNullAtRuntime);
+    io.enumCase(value, "at-buildtime",lld::UndefinedAtom::canBeNullAtBuildtime);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<ShlibCanBeNull> {
+  static void enumeration(IO &io, ShlibCanBeNull &value) {
+    io.enumCase(value, "never",      false);
+    io.enumCase(value, "at-runtime", true);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
+  static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
+    io.enumCase(value, "code",    lld::SharedLibraryAtom::Type::Code);
+    io.enumCase(value, "data",    lld::SharedLibraryAtom::Type::Data);
+    io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
+  }
+};
+
+/// This is a custom formatter for lld::DefinedAtom::Alignment.  Values look
+/// like:
+///     8           # 8-byte aligned
+///     7 mod 16    # 16-byte aligned plus 7 bytes
+template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
+  static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
+                     raw_ostream &out) {
+    if (value.modulus == 0) {
+      out << llvm::format("%d", value.value);
+    } else {
+      out << llvm::format("%d mod %d", value.modulus, value.value);
+    }
+  }
+
+  static StringRef input(StringRef scalar, void *ctxt,
+                         lld::DefinedAtom::Alignment &value) {
+    value.modulus = 0;
+    size_t modStart = scalar.find("mod");
+    if (modStart != StringRef::npos) {
+      StringRef modStr = scalar.slice(0, modStart);
+      modStr = modStr.rtrim();
+      unsigned int modulus;
+      if (modStr.getAsInteger(0, modulus)) {
+        return "malformed alignment modulus";
+      }
+      value.modulus = modulus;
+      scalar = scalar.drop_front(modStart + 3);
+      scalar = scalar.ltrim();
+    }
+    unsigned int power;
+    if (scalar.getAsInteger(0, power)) {
+      return "malformed alignment power";
+    }
+    value.value = power;
+    if (value.modulus >= power) {
+      return "malformed alignment, modulus too large for power";
+    }
+    return StringRef(); // returning empty string means success
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+template <> struct ScalarEnumerationTraits<FileKinds> {
+  static void enumeration(IO &io, FileKinds &value) {
+    io.enumCase(value, "object",        fileKindObjectAtoms);
+    io.enumCase(value, "archive",       fileKindArchive);
+    io.enumCase(value, "object-mach-o", fileKindObjectMachO);
+  }
+};
+
+template <> struct MappingTraits<ArchMember> {
+  static void mapping(IO &io, ArchMember &member) {
+    io.mapOptional("kind",    member._kind, fileKindObjectAtoms);
+    io.mapOptional("name",    member._name);
+    io.mapRequired("content", member._content);
+  }
+};
+
+// Declare that an AtomList is a yaml sequence.
+template <typename T> struct SequenceTraits<AtomList<T> > {
+  static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
+  static T *&element(IO &io, AtomList<T> &seq, size_t index) {
+    if (index >= seq._atoms.size())
+      seq._atoms.resize(index + 1);
+    return seq._atoms[index].get();
+  }
+};
+
+// Declare that an AtomRange is a yaml sequence.
+template <typename T> struct SequenceTraits<File::AtomRange<T> > {
+  static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
+  static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
+    assert(io.outputting() && "AtomRange only used when outputting");
+    assert(index < seq.size() && "Out of range access");
+    return seq[index].get();
+  }
+};
+
+// Used to allow DefinedAtom content bytes to be a flow sequence of
+// two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
+template <> struct ScalarTraits<ImplicitHex8> {
+  static void output(const ImplicitHex8 &val, void *, raw_ostream &out) {
+    uint8_t num = val;
+    out << llvm::format("%02X", num);
+  }
+
+  static StringRef input(StringRef str, void *, ImplicitHex8 &val) {
+    unsigned long long n;
+    if (getAsUnsignedInteger(str, 16, n))
+      return "invalid two-digit-hex number";
+    if (n > 0xFF)
+      return "out of range two-digit-hex number";
+    val = n;
+    return StringRef(); // returning empty string means success
+  }
+
+  static bool mustQuote(StringRef) { return false; }
+};
+
+// YAML conversion for std::vector<const lld::File*>
+template <> struct DocumentListTraits<std::vector<const lld::File *> > {
+  static size_t size(IO &io, std::vector<const lld::File *> &seq) {
+    return seq.size();
+  }
+  static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq,
+                                   size_t index) {
+    if (index >= seq.size())
+      seq.resize(index + 1);
+    return seq[index];
+  }
+};
+
+// YAML conversion for const lld::File*
+template <> struct MappingTraits<const lld::File *> {
+  class NormArchiveFile : public lld::ArchiveLibraryFile {
+  public:
+    NormArchiveFile(IO &io) : ArchiveLibraryFile("") {}
+
+    NormArchiveFile(IO &io, const lld::File *file)
+        : ArchiveLibraryFile(file->path()), _path(file->path()) {
+      // If we want to support writing archives, this constructor would
+      // need to populate _members.
+    }
+
+    const lld::File *denormalize(IO &io) { return this; }
+
+    const AtomRange<lld::DefinedAtom> defined() const override {
+      return _noDefinedAtoms;
+    }
+
+    const AtomRange<lld::UndefinedAtom> undefined() const override {
+      return _noUndefinedAtoms;
+    }
+
+    const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
+      return _noSharedLibraryAtoms;
+    }
+
+    const AtomRange<lld::AbsoluteAtom> absolute() const override {
+      return _noAbsoluteAtoms;
+    }
+
+    void clearAtoms() override {
+      _noDefinedAtoms.clear();
+      _noUndefinedAtoms.clear();
+      _noSharedLibraryAtoms.clear();
+      _noAbsoluteAtoms.clear();
+    }
+
+    File *find(StringRef name) override {
+      for (const ArchMember &member : _members)
+        for (const lld::DefinedAtom *atom : member._content->defined())
+          if (name == atom->name())
+            return const_cast<File *>(member._content);
+      return nullptr;
+    }
+
+    std::error_code
+    parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+      return std::error_code();
+    }
+
+    StringRef               _path;
+    std::vector<ArchMember> _members;
+  };
+
+  class NormalizedFile : public lld::File {
+  public:
+    NormalizedFile(IO &io)
+      : File("", kindNormalizedObject), _io(io), _rnb(nullptr),
+        _definedAtomsRef(_definedAtoms._atoms),
+        _undefinedAtomsRef(_undefinedAtoms._atoms),
+        _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
+        _absoluteAtomsRef(_absoluteAtoms._atoms) {}
+
+    NormalizedFile(IO &io, const lld::File *file)
+        : File(file->path(), kindNormalizedObject), _io(io),
+          _rnb(new RefNameBuilder(*file)), _path(file->path()),
+        _definedAtomsRef(file->defined()),
+        _undefinedAtomsRef(file->undefined()),
+        _sharedLibraryAtomsRef(file->sharedLibrary()),
+        _absoluteAtomsRef(file->absolute()) {
+    }
+
+    ~NormalizedFile() override {
+    }
+
+    const lld::File *denormalize(IO &io);
+
+    const AtomRange<lld::DefinedAtom> defined() const override {
+      return _definedAtomsRef;
+    }
+
+    const AtomRange<lld::UndefinedAtom> undefined() const override {
+      return _undefinedAtomsRef;
+    }
+
+    const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
+      return _sharedLibraryAtomsRef;
+    }
+
+    const AtomRange<lld::AbsoluteAtom> absolute() const override {
+      return _absoluteAtomsRef;
+    }
+
+    void clearAtoms() override {
+      _definedAtoms._atoms.clear();
+      _undefinedAtoms._atoms.clear();
+      _sharedLibraryAtoms._atoms.clear();
+      _absoluteAtoms._atoms.clear();
+    }
+
+    // Allocate a new copy of this string in _storage, so the strings
+    // can be freed when File is destroyed.
+    StringRef copyString(StringRef str) {
+      char *s = _storage.Allocate<char>(str.size());
+      memcpy(s, str.data(), str.size());
+      return StringRef(s, str.size());
+    }
+
+    IO                                  &_io;
+    std::unique_ptr<RefNameBuilder>      _rnb;
+    StringRef                            _path;
+    AtomList<lld::DefinedAtom>           _definedAtoms;
+    AtomList<lld::UndefinedAtom>         _undefinedAtoms;
+    AtomList<lld::SharedLibraryAtom>     _sharedLibraryAtoms;
+    AtomList<lld::AbsoluteAtom>          _absoluteAtoms;
+    AtomRange<lld::DefinedAtom>          _definedAtomsRef;
+    AtomRange<lld::UndefinedAtom>        _undefinedAtomsRef;
+    AtomRange<lld::SharedLibraryAtom>    _sharedLibraryAtomsRef;
+    AtomRange<lld::AbsoluteAtom>         _absoluteAtomsRef;
+    llvm::BumpPtrAllocator               _storage;
+  };
+
+  static void mapping(IO &io, const lld::File *&file) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    assert(info != nullptr);
+    // Let any register tag handler process this.
+    if (info->_registry && info->_registry->handleTaggedDoc(io, file))
+      return;
+    // If no registered handler claims this tag and there is no tag,
+    // grandfather in as "!native".
+    if (io.mapTag("!native", true) || io.mapTag("tag:yaml.org,2002:map"))
+      mappingAtoms(io, file);
+  }
+
+  static void mappingAtoms(IO &io, const lld::File *&file) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedFile, const lld::File *>
+      keys(io, file, nullptr);
+    assert(info != nullptr);
+    info->_file = keys.operator->();
+
+    io.mapOptional("path",                 keys->_path);
+
+    if (io.outputting()) {
+      io.mapOptional("defined-atoms",        keys->_definedAtomsRef);
+      io.mapOptional("undefined-atoms",      keys->_undefinedAtomsRef);
+      io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
+      io.mapOptional("absolute-atoms",       keys->_absoluteAtomsRef);
+    } else {
+      io.mapOptional("defined-atoms",        keys->_definedAtoms);
+      io.mapOptional("undefined-atoms",      keys->_undefinedAtoms);
+      io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
+      io.mapOptional("absolute-atoms",       keys->_absoluteAtoms);
+    }
+  }
+
+  static void mappingArchive(IO &io, const lld::File *&file) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormArchiveFile, const lld::File *>
+      keys(io, file, &info->_file->allocator());
+
+    io.mapOptional("path",    keys->_path);
+    io.mapOptional("members", keys->_members);
+  }
+};
+
+// YAML conversion for const lld::Reference*
+template <> struct MappingTraits<const lld::Reference *> {
+  class NormalizedReference : public lld::Reference {
+  public:
+    NormalizedReference(IO &io)
+        : lld::Reference(lld::Reference::KindNamespace::all,
+                         lld::Reference::KindArch::all, 0),
+          _target(nullptr), _offset(0), _addend(0), _tag(0) {}
+
+    NormalizedReference(IO &io, const lld::Reference *ref)
+        : lld::Reference(ref->kindNamespace(), ref->kindArch(),
+                         ref->kindValue()),
+          _target(nullptr), _targetName(targetName(io, ref)),
+          _offset(ref->offsetInAtom()), _addend(ref->addend()),
+          _tag(ref->tag()) {
+      _mappedKind.ns = ref->kindNamespace();
+      _mappedKind.arch = ref->kindArch();
+      _mappedKind.value = ref->kindValue();
+    }
+
+    const lld::Reference *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_targetName.empty())
+        _targetName = f->copyString(_targetName);
+      DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+                                        << "created Reference to name: '"
+                                        << _targetName << "' ("
+                                        << (const void *)_targetName.data()
+                                        << ", " << _targetName.size() << ")\n");
+      setKindNamespace(_mappedKind.ns);
+      setKindArch(_mappedKind.arch);
+      setKindValue(_mappedKind.value);
+      return this;
+    }
+
+    void bind(const RefNameResolver &);
+    static StringRef targetName(IO &io, const lld::Reference *ref);
+
+    uint64_t offsetInAtom() const override { return _offset; }
+    const lld::Atom *target() const override { return _target; }
+    Addend addend() const override { return _addend; }
+    void setAddend(Addend a) override { _addend = a; }
+    void setTarget(const lld::Atom *a) override { _target = a; }
+
+    const lld::Atom *_target;
+    StringRef        _targetName;
+    uint32_t         _offset;
+    Addend           _addend;
+    RefKind          _mappedKind;
+    uint32_t         _tag;
+  };
+
+  static void mapping(IO &io, const lld::Reference *&ref) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
+        io, ref, &info->_file->allocator());
+
+    io.mapRequired("kind",   keys->_mappedKind);
+    io.mapOptional("offset", keys->_offset);
+    io.mapOptional("target", keys->_targetName);
+    io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
+    io.mapOptional("tag",    keys->_tag, 0u);
+  }
+};
+
+// YAML conversion for const lld::DefinedAtom*
+template <> struct MappingTraits<const lld::DefinedAtom *> {
+
+  class NormalizedAtom : public lld::DefinedAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _contentType(), _alignment(1) {
+      static uint32_t ordinalCounter = 1;
+      _ordinal = ordinalCounter++;
+    }
+
+    NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()),
+          _scope(atom->scope()), _interpose(atom->interposable()),
+          _merge(atom->merge()), _contentType(atom->contentType()),
+          _alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()),
+          _deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()),
+          _codeModel(atom->codeModel()),
+          _permissions(atom->permissions()), _size(atom->size()),
+          _sectionName(atom->customSectionName()),
+          _sectionSize(atom->sectionSize()) {
+      for (const lld::Reference *r : *atom)
+        _references.push_back(r);
+      if (!atom->occupiesDiskSpace())
+        return;
+      ArrayRef<uint8_t> cont = atom->rawContent();
+      _content.reserve(cont.size());
+      for (uint8_t x : cont)
+        _content.push_back(x);
+    }
+
+    ~NormalizedAtom() override = default;
+
+    const lld::DefinedAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+      if (!_refName.empty())
+        _refName = f->copyString(_refName);
+      if (!_sectionName.empty())
+        _sectionName = f->copyString(_sectionName);
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created DefinedAtom named: '" << _name
+                                   << "' (" << (const void *)_name.data()
+                                   << ", " << _name.size() << ")\n");
+      return this;
+    }
+
+    void bind(const RefNameResolver &);
+
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    uint64_t size() const override { return _size; }
+    Scope scope() const override { return _scope; }
+    Interposable interposable() const override { return _interpose; }
+    Merge merge() const override { return _merge; }
+    ContentType contentType() const override { return _contentType; }
+    Alignment alignment() const override { return _alignment; }
+    SectionChoice sectionChoice() const override { return _sectionChoice; }
+    StringRef customSectionName() const override { return _sectionName; }
+    uint64_t sectionSize() const override { return _sectionSize; }
+    DeadStripKind deadStrip() const override { return _deadStrip; }
+    DynamicExport dynamicExport() const override { return _dynamicExport; }
+    CodeModel codeModel() const override { return _codeModel; }
+    ContentPermissions permissions() const override { return _permissions; }
+    ArrayRef<uint8_t> rawContent() const override {
+      if (!occupiesDiskSpace())
+        return ArrayRef<uint8_t>();
+      return ArrayRef<uint8_t>(
+          reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
+    }
+
+    uint64_t ordinal() const override { return _ordinal; }
+
+    reference_iterator begin() const override {
+      uintptr_t index = 0;
+      const void *it = reinterpret_cast<const void *>(index);
+      return reference_iterator(*this, it);
+    }
+    reference_iterator end() const override {
+      uintptr_t index = _references.size();
+      const void *it = reinterpret_cast<const void *>(index);
+      return reference_iterator(*this, it);
+    }
+    const lld::Reference *derefIterator(const void *it) const override {
+      uintptr_t index = reinterpret_cast<uintptr_t>(it);
+      assert(index < _references.size());
+      return _references[index];
+    }
+    void incrementIterator(const void *&it) const override {
+      uintptr_t index = reinterpret_cast<uintptr_t>(it);
+      ++index;
+      it = reinterpret_cast<const void *>(index);
+    }
+
+    void addReference(Reference::KindNamespace ns,
+                      Reference::KindArch arch,
+                      Reference::KindValue kindValue, uint64_t off,
+                      const Atom *target, Reference::Addend a) override {
+      assert(target && "trying to create reference to nothing");
+      auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
+                                                           off, target, a);
+      _references.push_back(node);
+    }
+
+    const lld::File                    &_file;
+    StringRef                           _name;
+    StringRef                           _refName;
+    Scope                               _scope;
+    Interposable                        _interpose;
+    Merge                               _merge;
+    ContentType                         _contentType;
+    Alignment                           _alignment;
+    SectionChoice                       _sectionChoice;
+    DeadStripKind                       _deadStrip;
+    DynamicExport                       _dynamicExport;
+    CodeModel                           _codeModel;
+    ContentPermissions                  _permissions;
+    uint32_t                            _ordinal;
+    std::vector<ImplicitHex8>           _content;
+    uint64_t                            _size;
+    StringRef                           _sectionName;
+    uint64_t                            _sectionSize;
+    std::vector<const lld::Reference *> _references;
+  };
+
+  static void mapping(IO &io, const lld::DefinedAtom *&atom) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
+        io, atom, &info->_file->allocator());
+    if (io.outputting()) {
+      // If writing YAML, check if atom needs a ref-name.
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      assert(info != nullptr);
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      assert(f);
+      assert(f->_rnb);
+      if (f->_rnb->hasRefName(atom)) {
+        keys->_refName = f->_rnb->refName(atom);
+      }
+    }
+
+    io.mapOptional("name",             keys->_name,    StringRef());
+    io.mapOptional("ref-name",         keys->_refName, StringRef());
+    io.mapOptional("scope",            keys->_scope,
+                                         DefinedAtom::scopeTranslationUnit);
+    io.mapOptional("type",             keys->_contentType,
+                                         DefinedAtom::typeCode);
+    io.mapOptional("content",          keys->_content);
+    io.mapOptional("size",             keys->_size, (uint64_t)keys->_content.size());
+    io.mapOptional("interposable",     keys->_interpose,
+                                         DefinedAtom::interposeNo);
+    io.mapOptional("merge",            keys->_merge, DefinedAtom::mergeNo);
+    io.mapOptional("alignment",        keys->_alignment,
+                                         DefinedAtom::Alignment(1));
+    io.mapOptional("section-choice",   keys->_sectionChoice,
+                                         DefinedAtom::sectionBasedOnContent);
+    io.mapOptional("section-name",     keys->_sectionName, StringRef());
+    io.mapOptional("section-size",     keys->_sectionSize, (uint64_t)0);
+    io.mapOptional("dead-strip",       keys->_deadStrip,
+                                         DefinedAtom::deadStripNormal);
+    io.mapOptional("dynamic-export",   keys->_dynamicExport,
+                                         DefinedAtom::dynamicExportNormal);
+    io.mapOptional("code-model",       keys->_codeModel, DefinedAtom::codeNA);
+    // default permissions based on content type
+    io.mapOptional("permissions",      keys->_permissions,
+                                         DefinedAtom::permissions(
+                                                          keys->_contentType));
+    io.mapOptional("references",       keys->_references);
+  }
+};
+
+template <> struct MappingTraits<lld::DefinedAtom *> {
+  static void mapping(IO &io, lld::DefinedAtom *&atom) {
+    const lld::DefinedAtom *atomPtr = atom;
+    MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::DefinedAtom *>(atomPtr);
+  }
+};
+
+// YAML conversion for const lld::UndefinedAtom*
+template <> struct MappingTraits<const lld::UndefinedAtom *> {
+  class NormalizedAtom : public lld::UndefinedAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _canBeNull(canBeNullNever) {}
+
+    NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()),
+          _canBeNull(atom->canBeNull()) {}
+
+    ~NormalizedAtom() override = default;
+
+    const lld::UndefinedAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created UndefinedAtom named: '" << _name
+                      << "' (" << (const void *)_name.data() << ", "
+                      << _name.size() << ")\n");
+      return this;
+    }
+
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    CanBeNull canBeNull() const override { return _canBeNull; }
+
+    const lld::File     &_file;
+    StringRef            _name;
+    CanBeNull            _canBeNull;
+  };
+
+  static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
+        io, atom, &info->_file->allocator());
+
+    io.mapRequired("name",        keys->_name);
+    io.mapOptional("can-be-null", keys->_canBeNull,
+                                  lld::UndefinedAtom::canBeNullNever);
+  }
+};
+
+template <> struct MappingTraits<lld::UndefinedAtom *> {
+  static void mapping(IO &io, lld::UndefinedAtom *&atom) {
+    const lld::UndefinedAtom *atomPtr = atom;
+    MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::UndefinedAtom *>(atomPtr);
+  }
+};
+
+// YAML conversion for const lld::SharedLibraryAtom*
+template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
+  class NormalizedAtom : public lld::SharedLibraryAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _canBeNull(false),
+          _type(Type::Unknown), _size(0) {}
+
+    NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()),
+          _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
+          _type(atom->type()), _size(atom->size()) {}
+
+    ~NormalizedAtom() override = default;
+
+    const lld::SharedLibraryAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+      if (!_loadName.empty())
+        _loadName = f->copyString(_loadName);
+
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created SharedLibraryAtom named: '"
+                                   << _name << "' ("
+                                   << (const void *)_name.data()
+                                   << ", " << _name.size() << ")\n");
+      return this;
+    }
+
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    StringRef loadName() const override { return _loadName; }
+    bool canBeNullAtRuntime() const override { return _canBeNull; }
+    Type type() const override { return _type; }
+    uint64_t size() const override { return _size; }
+
+    const lld::File &_file;
+    StringRef        _name;
+    StringRef        _loadName;
+    ShlibCanBeNull   _canBeNull;
+    Type             _type;
+    uint64_t         _size;
+  };
+
+  static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
+
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
+    keys(io, atom, &info->_file->allocator());
+
+    io.mapRequired("name",        keys->_name);
+    io.mapOptional("load-name",   keys->_loadName);
+    io.mapOptional("can-be-null", keys->_canBeNull, (ShlibCanBeNull) false);
+    io.mapOptional("type",        keys->_type, SharedLibraryAtom::Type::Code);
+    io.mapOptional("size",        keys->_size, uint64_t(0));
+  }
+};
+
+template <> struct MappingTraits<lld::SharedLibraryAtom *> {
+  static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
+    const lld::SharedLibraryAtom *atomPtr = atom;
+    MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
+  }
+};
+
+// YAML conversion for const lld::AbsoluteAtom*
+template <> struct MappingTraits<const lld::AbsoluteAtom *> {
+  class NormalizedAtom : public lld::AbsoluteAtom {
+  public:
+    NormalizedAtom(IO &io)
+        : _file(fileFromContext(io)), _scope(), _value(0) {}
+
+    NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
+        : _file(fileFromContext(io)), _name(atom->name()),
+          _scope(atom->scope()), _value(atom->value()) {}
+
+    ~NormalizedAtom() override = default;
+
+    const lld::AbsoluteAtom *denormalize(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      if (!_name.empty())
+        _name = f->copyString(_name);
+
+      DEBUG_WITH_TYPE("WriterYAML",
+                      llvm::dbgs() << "created AbsoluteAtom named: '" << _name
+                                   << "' (" << (const void *)_name.data()
+                                   << ", " << _name.size() << ")\n");
+      return this;
+    }
+
+    // Extract current File object from YAML I/O parsing context
+    const lld::File &fileFromContext(IO &io) {
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      assert(info->_file != nullptr);
+      return *info->_file;
+    }
+
+    const lld::File &file() const override { return _file; }
+    StringRef name() const override { return _name; }
+    uint64_t value() const override { return _value; }
+    Scope scope() const override { return _scope; }
+
+    const lld::File &_file;
+    StringRef        _name;
+    StringRef        _refName;
+    Scope            _scope;
+    Hex64            _value;
+  };
+
+  static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
+    YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+    MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
+        io, atom, &info->_file->allocator());
+
+    if (io.outputting()) {
+      typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+      YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+      assert(info != nullptr);
+      NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+      assert(f);
+      assert(f->_rnb);
+      if (f->_rnb->hasRefName(atom)) {
+        keys->_refName = f->_rnb->refName(atom);
+      }
+    }
+
+    io.mapRequired("name",     keys->_name);
+    io.mapOptional("ref-name", keys->_refName, StringRef());
+    io.mapOptional("scope",    keys->_scope);
+    io.mapRequired("value",    keys->_value);
+  }
+};
+
+template <> struct MappingTraits<lld::AbsoluteAtom *> {
+  static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
+    const lld::AbsoluteAtom *atomPtr = atom;
+    MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
+    atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
+  }
+};
+
+} // end namespace llvm
+} // end namespace yaml
+
+RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
+  typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
+  NormalizedAtom;
+  for (const lld::DefinedAtom *a : file->defined()) {
+    const auto *na = (const NormalizedAtom *)a;
+    if (!na->_refName.empty())
+      add(na->_refName, a);
+    else if (!na->_name.empty())
+      add(na->_name, a);
+  }
+
+  for (const lld::UndefinedAtom *a : file->undefined())
+    add(a->name(), a);
+
+  for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
+    add(a->name(), a);
+
+  typedef MappingTraits<const lld::AbsoluteAtom *>::NormalizedAtom NormAbsAtom;
+  for (const lld::AbsoluteAtom *a : file->absolute()) {
+    const auto *na = (const NormAbsAtom *)a;
+    if (na->_refName.empty())
+      add(na->_name, a);
+    else
+      add(na->_refName, a);
+  }
+}
+
+inline const lld::File *
+MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
+  typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
+  NormalizedAtom;
+
+  RefNameResolver nameResolver(this, io);
+  // Now that all atoms are parsed, references can be bound.
+  for (const lld::DefinedAtom *a : this->defined()) {
+    auto *normAtom = (NormalizedAtom *)const_cast<DefinedAtom *>(a);
+    normAtom->bind(nameResolver);
+  }
+
+  return this;
+}
+
+inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
+    const RefNameResolver &resolver) {
+  typedef MappingTraits<const lld::Reference *>::NormalizedReference
+  NormalizedReference;
+  for (const lld::Reference *ref : _references) {
+    auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
+    normRef->bind(resolver);
+  }
+}
+
+inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
+    const RefNameResolver &resolver) {
+  _target = resolver.lookup(_targetName);
+}
+
+inline StringRef
+MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
+    IO &io, const lld::Reference *ref) {
+  if (ref->target() == nullptr)
+    return StringRef();
+  YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+  assert(info != nullptr);
+  typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+  NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+  RefNameBuilder &rnb = *f->_rnb;
+  if (rnb.hasRefName(ref->target()))
+    return rnb.refName(ref->target());
+  return ref->target()->name();
+}
+
+namespace lld {
+namespace yaml {
+
+class Writer : public lld::Writer {
+public:
+  Writer(const LinkingContext &context) : _ctx(context) {}
+
+  llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
+    // Create stream to path.
+    std::error_code ec;
+    llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
+    if (ec)
+      return llvm::errorCodeToError(ec);
+
+    // Create yaml Output writer, using yaml options for context.
+    YamlContext yamlContext;
+    yamlContext._ctx = &_ctx;
+    yamlContext._registry = &_ctx.registry();
+    llvm::yaml::Output yout(out, &yamlContext);
+
+    // Write yaml output.
+    const lld::File *fileRef = &file;
+    yout << fileRef;
+
+    return llvm::Error::success();
+  }
+
+private:
+  const LinkingContext &_ctx;
+};
+
+} // end namespace yaml
+
+namespace {
+
+/// Handles !native tagged yaml documents.
+class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+  bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
+    if (io.mapTag("!native")) {
+      MappingTraits<const lld::File *>::mappingAtoms(io, file);
+      return true;
+    }
+    return false;
+  }
+};
+
+/// Handles !archive tagged yaml documents.
+class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+  bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
+    if (io.mapTag("!archive")) {
+      MappingTraits<const lld::File *>::mappingArchive(io, file);
+      return true;
+    }
+    return false;
+  }
+};
+
+class YAMLReader : public Reader {
+public:
+  YAMLReader(const Registry &registry) : _registry(registry) {}
+
+  bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+    StringRef name = mb.getBufferIdentifier();
+    return name.endswith(".objtxt") || name.endswith(".yaml");
+  }
+
+  ErrorOr<std::unique_ptr<File>>
+  loadFile(std::unique_ptr<MemoryBuffer> mb,
+           const class Registry &) const override {
+    // Create YAML Input Reader.
+    YamlContext yamlContext;
+    yamlContext._registry = &_registry;
+    yamlContext._path = mb->getBufferIdentifier();
+    llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
+
+    // Fill vector with File objects created by parsing yaml.
+    std::vector<const lld::File *> createdFiles;
+    yin >> createdFiles;
+    assert(createdFiles.size() == 1);
+
+    // Error out now if there were parsing errors.
+    if (yin.error())
+      return make_error_code(lld::YamlReaderError::illegal_value);
+
+    std::shared_ptr<MemoryBuffer> smb(mb.release());
+    const File *file = createdFiles[0];
+    // Note: loadFile() should return vector of *const* File
+    File *f = const_cast<File *>(file);
+    f->setLastError(std::error_code());
+    f->setSharedMemoryBuffer(smb);
+    return std::unique_ptr<File>(f);
+  }
+
+private:
+  const Registry &_registry;
+};
+
+} // end anonymous namespace
+
+void Registry::addSupportYamlFiles() {
+  add(std::unique_ptr<Reader>(new YAMLReader(*this)));
+  add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+                                    new NativeYamlIOTaggedDocumentHandler()));
+  add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+                                    new ArchiveYamlIOTaggedDocumentHandler()));
+}
+
+std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
+  return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
+}
+
+} // end namespace lld
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1dbd1b7
--- /dev/null
@@ -0,0 +1,56 @@
+set(LLVM_SOURCE_DIR "${LLVM_MAIN_SRC_DIR}")
+set(LLVM_BINARY_DIR "${LLVM_BINARY_DIR}")
+set(LLVM_BUILD_MODE "%(build_mode)s")
+set(LLVM_TOOLS_DIR "${LLVM_TOOLS_BINARY_DIR}/%(build_config)s")
+set(LLVM_LIBS_DIR "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/%(build_config)s")
+
+if(LLD_BUILT_STANDALONE)
+  # Set HAVE_LIBZ according to recorded LLVM_ENABLE_ZLIB value. This
+  # value is forced to 0 if zlib was not found, so it is fine to use it
+  # instead of HAVE_LIBZ (not recorded).
+  if(LLVM_ENABLE_ZLIB)
+    set(HAVE_LIBZ 1)
+  endif()
+endif()
+
+llvm_canonicalize_cmake_booleans(
+  HAVE_LIBZ)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+  )
+
+set(LLD_TEST_DEPS lld)
+if (NOT LLD_BUILT_STANDALONE)
+  list(APPEND LLD_TEST_DEPS
+    FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm
+    llc llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml
+    llvm-mc llvm-lib llvm-pdbutil opt
+    )
+endif()
+
+if (LLVM_INCLUDE_TESTS)
+  list(APPEND LLD_TEST_DEPS LLDUnitTests)
+endif()
+
+set(LLD_TEST_PARAMS
+  lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+  )
+
+add_lit_testsuite(check-lld "Running lld test suite"
+  ${CMAKE_CURRENT_BINARY_DIR}
+  PARAMS lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+       lld_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+  DEPENDS ${LLD_TEST_DEPS}
+  )
+
+set_target_properties(check-lld PROPERTIES FOLDER "lld tests")
+
+# Add a legacy target spelling: lld-test
+add_custom_target(lld-test)
+add_dependencies(lld-test check-lld)
+set_target_properties(lld-test PROPERTIES FOLDER "lld tests")
diff --git a/test/COFF/Inputs/armnt-executable.obj.yaml b/test/COFF/Inputs/armnt-executable.obj.yaml
new file mode 100644 (file)
index 0000000..5c42b90
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '7047'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          2
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            mainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/armnt-executable.s b/test/COFF/Inputs/armnt-executable.s
new file mode 100644 (file)
index 0000000..7e1a8ce
--- /dev/null
@@ -0,0 +1,13 @@
+# void mainCRTStartup() {}
+       .syntax unified
+       .thumb
+       .text
+       .def mainCRTStartup
+               .scl 2
+               .type 32
+       .endef
+       .global mainCRTStartup
+       .align 2
+       .thumb_func
+mainCRTStartup:
+       bx lr
diff --git a/test/COFF/Inputs/associative-comdat-2.s b/test/COFF/Inputs/associative-comdat-2.s
new file mode 100644 (file)
index 0000000..cd4ef46
--- /dev/null
@@ -0,0 +1,13 @@
+# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
+# associative with it. foo_assoc should be discarded iff foo is discarded,
+# either by linker GC or normal comdat merging.
+
+        .section        .rdata,"dr",associative,foo
+        .p2align        3
+        .quad   foo
+
+        .section        .data,"dw",discard,foo
+        .globl  foo                     # @foo
+        .p2align        2
+foo:
+        .long   42
diff --git a/test/COFF/Inputs/bar.ll b/test/COFF/Inputs/bar.ll
new file mode 100644 (file)
index 0000000..4aed5d2
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @bar() {
+  ret void
+}
diff --git a/test/COFF/Inputs/cl-gl.obj b/test/COFF/Inputs/cl-gl.obj
new file mode 100755 (executable)
index 0000000..ff74655
Binary files /dev/null and b/test/COFF/Inputs/cl-gl.obj differ
diff --git a/test/COFF/Inputs/combined-resources-2.rc b/test/COFF/Inputs/combined-resources-2.rc
new file mode 100644 (file)
index 0000000..081b3a7
--- /dev/null
@@ -0,0 +1,36 @@
+#include "windows.h"\r
+\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+randomdat RCDATA\r
+{\r
+       "this is a random bit of data that means nothing\0",\r
+       0x23a9,\r
+       0x140e,\r
+       194292,\r
+}\r
+\r
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED\r
+randomdat RCDATA\r
+{\r
+       "zhe4 shi4 yi1ge4 sui2ji1 de shu4ju4, zhe4 yi4wei4zhe shen2me\0",\r
+       0x23a9,\r
+       0x140e,\r
+       194292,\r
+}\r
+\r
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG\r
+randomdat RCDATA\r
+{\r
+       "Dies ist ein zufälliges Bit von Daten, die nichts bedeutet\0",\r
+       0x23a9,\r
+       0x140e,\r
+       194292,\r
+}\r
+\r
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED\r
+myaccelerators ACCELERATORS\r
+{\r
+       "^C", 999, VIRTKEY, ALT\r
+       "D", 1100, VIRTKEY, CONTROL, SHIFT\r
+       "^R", 444, ASCII, NOINVERT\r
+}\r
diff --git a/test/COFF/Inputs/combined-resources-2.res b/test/COFF/Inputs/combined-resources-2.res
new file mode 100644 (file)
index 0000000..31da616
Binary files /dev/null and b/test/COFF/Inputs/combined-resources-2.res differ
diff --git a/test/COFF/Inputs/combined-resources-cursor.bmp b/test/COFF/Inputs/combined-resources-cursor.bmp
new file mode 100644 (file)
index 0000000..ce51326
Binary files /dev/null and b/test/COFF/Inputs/combined-resources-cursor.bmp differ
diff --git a/test/COFF/Inputs/combined-resources-okay.bmp b/test/COFF/Inputs/combined-resources-okay.bmp
new file mode 100644 (file)
index 0000000..e4005bf
Binary files /dev/null and b/test/COFF/Inputs/combined-resources-okay.bmp differ
diff --git a/test/COFF/Inputs/combined-resources.rc b/test/COFF/Inputs/combined-resources.rc
new file mode 100644 (file)
index 0000000..08bfb94
--- /dev/null
@@ -0,0 +1,50 @@
+#include "windows.h"\r
+\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+\r
+myaccelerators ACCELERATORS\r
+{\r
+       "^C", 999, VIRTKEY, ALT\r
+       "D", 1100, VIRTKEY, CONTROL, SHIFT\r
+       "^R", 444, ASCII, NOINVERT\r
+}\r
+\r
+cursor BITMAP "combined-resources-cursor.bmp"\r
+okay BITMAP "combined-resources-okay.bmp"\r
+\r
+14432 MENU\r
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED\r
+{\r
+       MENUITEM "yu", 100\r
+       MENUITEM "shala", 101\r
+       MENUITEM "kaoya", 102\r
+}\r
+\r
+testdialog DIALOG 10, 10, 200, 300\r
+STYLE WS_POPUP | WS_BORDER\r
+CAPTION "Test"\r
+{\r
+       CTEXT "Continue:", 1, 10, 10, 230, 14\r
+       PUSHBUTTON "&OK", 2, 66, 134, 161, 13\r
+}\r
+\r
+12 ACCELERATORS\r
+{\r
+       "X", 164, VIRTKEY, ALT\r
+       "H", 5678, VIRTKEY, CONTROL, SHIFT\r
+       "^R", 444, ASCII, NOINVERT\r
+}\r
+\r
+"eat" MENU\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS\r
+{\r
+       MENUITEM "fish", 100\r
+       MENUITEM "salad", 101\r
+       MENUITEM "duck", 102\r
+}\r
+\r
+\r
+myresource stringarray {\r
+       "this is a user defined resource\0",\r
+       "it contains many strings\0",\r
+}\r
diff --git a/test/COFF/Inputs/combined-resources.res b/test/COFF/Inputs/combined-resources.res
new file mode 100644 (file)
index 0000000..d422bb4
Binary files /dev/null and b/test/COFF/Inputs/combined-resources.res differ
diff --git a/test/COFF/Inputs/conflict.ll b/test/COFF/Inputs/conflict.ll
new file mode 100644 (file)
index 0000000..8cd7d70
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo() {
+  ret void
+}
diff --git a/test/COFF/Inputs/constant-export.ll b/test/COFF/Inputs/constant-export.ll
new file mode 100644 (file)
index 0000000..666c18f
--- /dev/null
@@ -0,0 +1,7 @@
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i686-unknown-windows-msvc18.0.0"
+
+@__CFConstantStringClassReference = common global [32 x i32] zeroinitializer, align 4
+
+!llvm.linker.options = !{!0}
+!0 = !{!" -export:___CFConstantStringClassReference,CONSTANT"}
diff --git a/test/COFF/Inputs/constant-import.s b/test/COFF/Inputs/constant-import.s
new file mode 100644 (file)
index 0000000..4249d74
--- /dev/null
@@ -0,0 +1,21 @@
+
+       .def __DllMainCRTStartup@12
+               .type 32
+               .scl 2
+       .endef
+       .global __DllMainCRTStartup@12
+__DllMainCRTStartup@12:
+       ret
+
+       .data
+       .def _Data
+               .type 0
+               .scl 2
+       .endef
+       .global _Data
+_Data:
+       .long ___CFConstantStringClassReference
+
+       .section .drectve
+       .ascii " -export:_Data"
+
diff --git a/test/COFF/Inputs/default.def b/test/COFF/Inputs/default.def
new file mode 100644 (file)
index 0000000..1d59bee
--- /dev/null
@@ -0,0 +1,2 @@
+EXPORTS
+  f
diff --git a/test/COFF/Inputs/delayimports-error.yaml b/test/COFF/Inputs/delayimports-error.yaml
new file mode 100644 (file)
index 0000000..60b3959
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .data
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            datasym
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/entry-mangled.ll b/test/COFF/Inputs/entry-mangled.ll
new file mode 100644 (file)
index 0000000..b6fac21
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc18.0.0"
+
+define void @"\01?main@@YAHXZ"() {
+  ret void
+}
diff --git a/test/COFF/Inputs/export.ll b/test/COFF/Inputs/export.ll
new file mode 100644 (file)
index 0000000..d254683
--- /dev/null
@@ -0,0 +1,18 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @_DllMainCRTStartup() {
+  ret void
+}
+
+define void @exportfn1() {
+  ret void
+}
+
+define void @exportfn2() {
+  ret void
+}
+
+define dllexport void @exportfn3() {
+  ret void
+}
diff --git a/test/COFF/Inputs/export.yaml b/test/COFF/Inputs/export.yaml
new file mode 100644 (file)
index 0000000..1ccf090
--- /dev/null
@@ -0,0 +1,57 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f6578706f72743a6578706f7274666e3300  # /export:exportfn3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _DllMainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1
+    Value:           8
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn2
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn3
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?mangled@@YAHXZ'
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/export2.yaml b/test/COFF/Inputs/export2.yaml
new file mode 100644 (file)
index 0000000..37fa4c7
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '?mangled2@@YAHXZ'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/extension.def b/test/COFF/Inputs/extension.def
new file mode 100644 (file)
index 0000000..d93f0dc
--- /dev/null
@@ -0,0 +1,3 @@
+LIBRARY library.ext
+EXPORTS
+  f
diff --git a/test/COFF/Inputs/far-arm-thumb-abs.s b/test/COFF/Inputs/far-arm-thumb-abs.s
new file mode 100644 (file)
index 0000000..9f1b59a
--- /dev/null
@@ -0,0 +1,2 @@
+.global too_far1
+too_far1 = 0x1401004
diff --git a/test/COFF/Inputs/hello32.yaml b/test/COFF/Inputs/hello32.yaml
new file mode 100644 (file)
index 0000000..09e76f1
--- /dev/null
@@ -0,0 +1,82 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     33DB538D0500000000508D05000000005053E80000000050E800000000
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      caption
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  19
+        SymbolName:      '_MessageBoxA@16'
+        Type:            IMAGE_REL_I386_REL32
+      - VirtualAddress:  25
+        SymbolName:      '_ExitProcess@4'
+        Type:            IMAGE_REL_I386_REL32
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       16
+    SectionData:     48656C6C6F0048656C6C6F20576F726C642100
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          29
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          19
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '_ExitProcess@4'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '_MessageBoxA@16'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            message
+    Value:           6
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            caption
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '_main@0'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/hello64.asm b/test/COFF/Inputs/hello64.asm
new file mode 100644 (file)
index 0000000..6605213
--- /dev/null
@@ -0,0 +1,24 @@
+;; ml64 hello64.asm /link /subsystem:windows /defaultlib:kernel32 \
+;;    /defaultlib:user32 /out:hello64.exe /entry:main
+
+extern ExitProcess : PROC
+extern MessageBoxA : PROC
+extern ImportByOrdinal: PROC
+
+.data
+        caption db 'Hello', 0
+        message db 'Hello World!', 0
+
+.code
+main PROC
+        sub rsp,28h
+        mov rcx, 0
+        lea rdx, message
+        lea r8, caption
+        mov r9d, 0
+        call MessageBoxA
+        mov ecx, 0
+        call ExitProcess
+        call ImportByOrdinal
+main ENDP
+END
diff --git a/test/COFF/Inputs/hello64.obj b/test/COFF/Inputs/hello64.obj
new file mode 100644 (file)
index 0000000..90c1ce4
Binary files /dev/null and b/test/COFF/Inputs/hello64.obj differ
diff --git a/test/COFF/Inputs/import.yaml b/test/COFF/Inputs/import.yaml
new file mode 100644 (file)
index 0000000..b7ae026
--- /dev/null
@@ -0,0 +1,48 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     0000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      exportfn1
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      exportfn2
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn2
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/imports-mangle.lib b/test/COFF/Inputs/imports-mangle.lib
new file mode 100644 (file)
index 0000000..f3c722a
Binary files /dev/null and b/test/COFF/Inputs/imports-mangle.lib differ
diff --git a/test/COFF/Inputs/include1a.yaml b/test/COFF/Inputs/include1a.yaml
new file mode 100644 (file)
index 0000000..f61e0e0
--- /dev/null
@@ -0,0 +1,33 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f696e636c7564653a666f6f00  # /include:foo
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/include1b.yaml b/test/COFF/Inputs/include1b.yaml
new file mode 100644 (file)
index 0000000..78d1b92
--- /dev/null
@@ -0,0 +1,33 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f696e636c7564653a62617200  # /include:bar
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/include1c.yaml b/test/COFF/Inputs/include1c.yaml
new file mode 100644 (file)
index 0000000..6cf9db6
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            bar
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/library-arm64.lib b/test/COFF/Inputs/library-arm64.lib
new file mode 100644 (file)
index 0000000..04e193d
Binary files /dev/null and b/test/COFF/Inputs/library-arm64.lib differ
diff --git a/test/COFF/Inputs/library.def b/test/COFF/Inputs/library.def
new file mode 100644 (file)
index 0000000..6c6880f
--- /dev/null
@@ -0,0 +1,5 @@
+LIBRARY library
+EXPORTS
+  function
+  data DATA
+  constant CONSTANT
diff --git a/test/COFF/Inputs/library.lib b/test/COFF/Inputs/library.lib
new file mode 100755 (executable)
index 0000000..2f4207d
Binary files /dev/null and b/test/COFF/Inputs/library.lib differ
diff --git a/test/COFF/Inputs/lto-chkstk-chkstk.s b/test/COFF/Inputs/lto-chkstk-chkstk.s
new file mode 100644 (file)
index 0000000..292b30d
--- /dev/null
@@ -0,0 +1,3 @@
+.globl __chkstk
+__chkstk:
+ret
diff --git a/test/COFF/Inputs/lto-chkstk-foo.s b/test/COFF/Inputs/lto-chkstk-foo.s
new file mode 100644 (file)
index 0000000..a69f870
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+ret
diff --git a/test/COFF/Inputs/lto-comdat1.ll b/test/COFF/Inputs/lto-comdat1.ll
new file mode 100644 (file)
index 0000000..7a9f50c
--- /dev/null
@@ -0,0 +1,13 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$comdat = comdat any
+
+define void @f1() {
+  call void @comdat()
+  ret void
+}
+
+define linkonce_odr void @comdat() comdat {
+  ret void
+}
diff --git a/test/COFF/Inputs/lto-comdat2.ll b/test/COFF/Inputs/lto-comdat2.ll
new file mode 100644 (file)
index 0000000..c2af2a4
--- /dev/null
@@ -0,0 +1,13 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$comdat = comdat any
+
+define void @f2() {
+  call void @comdat()
+  ret void
+}
+
+define linkonce_odr void @comdat() comdat {
+  ret void
+}
diff --git a/test/COFF/Inputs/lto-dep.ll b/test/COFF/Inputs/lto-dep.ll
new file mode 100644 (file)
index 0000000..d6d47f2
--- /dev/null
@@ -0,0 +1,10 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo() {
+  ret void
+}
+
+define internal void @internal() {
+  ret void
+}
diff --git a/test/COFF/Inputs/lto-lazy-reference-dummy.ll b/test/COFF/Inputs/lto-lazy-reference-dummy.ll
new file mode 100644 (file)
index 0000000..0309f89
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i686-pc-windows-msvc18.0.0"
+
+define void @dummy() {
+  ret void
+}
diff --git a/test/COFF/Inputs/lto-lazy-reference-quadruple.ll b/test/COFF/Inputs/lto-lazy-reference-quadruple.ll
new file mode 100644 (file)
index 0000000..99c1d2b
--- /dev/null
@@ -0,0 +1,16 @@
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i686-pc-windows-msvc18.0.0"
+
+define double @quadruple(double %x) {
+entry:
+  ; The symbol __real@40800000 is used to materialize the 4.0 constant.
+  %mul = fmul double %x, 4.0
+  ret double %mul
+}
+
+
+declare void @dummy()
+define void @f() {
+  call void @dummy()
+  ret void
+}
diff --git a/test/COFF/Inputs/machine-x64.yaml b/test/COFF/Inputs/machine-x64.yaml
new file mode 100644 (file)
index 0000000..36bdfe6
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/machine-x86.yaml b/test/COFF/Inputs/machine-x86.yaml
new file mode 100644 (file)
index 0000000..197143b
--- /dev/null
@@ -0,0 +1,29 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/manifestinput.test b/test/COFF/Inputs/manifestinput.test
new file mode 100644 (file)
index 0000000..c657392
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity type='win32'
+                        name='Microsoft.Windows.Common-Controls'
+                        version='6.0.0.0'
+                        processorArchitecture='*'
+                        publicKeyToken='6595b64144ccf1df'
+                        language='*' />
+    </dependentAssembly>
+  </dependency>
+</assembly>
diff --git a/test/COFF/Inputs/msvclto-order-a.ll b/test/COFF/Inputs/msvclto-order-a.ll
new file mode 100644 (file)
index 0000000..804e201
--- /dev/null
@@ -0,0 +1,7 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo() {
+  ret void
+}
+
diff --git a/test/COFF/Inputs/msvclto-order-b.ll b/test/COFF/Inputs/msvclto-order-b.ll
new file mode 100644 (file)
index 0000000..57f2389
--- /dev/null
@@ -0,0 +1,10 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare void @doesntexist()
+
+define void @foo() {
+  call void @doesntexist()
+  ret void
+}
+
diff --git a/test/COFF/Inputs/msvclto.s b/test/COFF/Inputs/msvclto.s
new file mode 100644 (file)
index 0000000..a69f870
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+ret
diff --git a/test/COFF/Inputs/named.def b/test/COFF/Inputs/named.def
new file mode 100644 (file)
index 0000000..07c8622
--- /dev/null
@@ -0,0 +1,3 @@
+LIBRARY library
+EXPORTS
+  f
diff --git a/test/COFF/Inputs/object.s b/test/COFF/Inputs/object.s
new file mode 100644 (file)
index 0000000..b705993
--- /dev/null
@@ -0,0 +1,13 @@
+
+       .text
+
+       .def f
+               .scl 2
+               .type 32
+       .endef
+       .global f
+f:
+       retq $0
+
+       .section .drectve,"rd"
+       .ascii " /EXPORT:f"
diff --git a/test/COFF/Inputs/oldname.yaml b/test/COFF/Inputs/oldname.yaml
new file mode 100644 (file)
index 0000000..42ee5b2
--- /dev/null
@@ -0,0 +1,26 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_UNKNOWN
+  Characteristics: [  ]
+sections:
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     ''
+symbols:
+  - Name:            exportfn1
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1_alias
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_WEAK_EXTERNAL
+    WeakExternal:
+      TagIndex:        0
+      Characteristics: IMAGE_WEAK_EXTERN_SEARCH_ALIAS
+...
diff --git a/test/COFF/Inputs/pdb-diff-cl.pdb b/test/COFF/Inputs/pdb-diff-cl.pdb
new file mode 100644 (file)
index 0000000..ba5d838
Binary files /dev/null and b/test/COFF/Inputs/pdb-diff-cl.pdb differ
diff --git a/test/COFF/Inputs/pdb-diff.cpp b/test/COFF/Inputs/pdb-diff.cpp
new file mode 100644 (file)
index 0000000..7c5d137
--- /dev/null
@@ -0,0 +1,10 @@
+// Build with cl:\r
+//    cl.exe /Z7 pdb-diff.cpp /link /debug /pdb:pdb-diff-cl.pdb\r
+//           /nodefaultlib /entry:main\r
+// Build with lld (after running the above cl command):\r
+//    lld-link.exe /debug /pdb:pdb-diff-lld.pdb /nodefaultlib\r
+//                 /entry:main pdb-diff.obj\r
+\r
+void *__purecall = 0;\r
+\r
+int main() { return 42; }\r
diff --git a/test/COFF/Inputs/pdb-diff.obj b/test/COFF/Inputs/pdb-diff.obj
new file mode 100644 (file)
index 0000000..a8948bd
Binary files /dev/null and b/test/COFF/Inputs/pdb-diff.obj differ
diff --git a/test/COFF/Inputs/pdb-global-gc.s b/test/COFF/Inputs/pdb-global-gc.s
new file mode 100644 (file)
index 0000000..4c931dc
--- /dev/null
@@ -0,0 +1,4 @@
+.section .data,"dw",one_only,__wc_mb_cur
+.global __wc_mb_cur
+__wc_mb_cur:
+.long 42
diff --git a/test/COFF/Inputs/pdb-import-gc.lib b/test/COFF/Inputs/pdb-import-gc.lib
new file mode 100644 (file)
index 0000000..f4682ed
Binary files /dev/null and b/test/COFF/Inputs/pdb-import-gc.lib differ
diff --git a/test/COFF/Inputs/pdb-scopes-a.yaml b/test/COFF/Inputs/pdb-scopes-a.yaml
new file mode 100644 (file)
index 0000000..e9f4484
--- /dev/null
@@ -0,0 +1,425 @@
+--- !COFF
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:        
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_OBJNAME
+            ObjNameSym:      
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\a.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:     
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              CodeSize:        5
+              DbgStart:        4
+              DbgEnd:          4
+              FunctionType:    4099
+              Flags:           [  ]
+              DisplayName:     g
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_REGREL32
+            RegRelativeSym:  
+              Offset:          8
+              Type:            116
+              Register:        RSP
+              VarName:         x
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        5
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\a.c'
+            Lines:           
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              CodeSize:        58
+              DbgStart:        8
+              DbgEnd:          53
+              FunctionType:    4101
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 56
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_REGREL32
+            RegRelativeSym:  
+              Offset:          64
+              Type:            116
+              Register:        RSP
+              VarName:         argc
+          - Kind:            S_BLOCK32
+            BlockSym:        
+              CodeSize:        17
+              Offset:          15
+              BlockName:       ''
+          - Kind:            S_REGREL32
+            RegRelativeSym:  
+              Offset:          32
+              Type:            116
+              Register:        RSP
+              VarName:         x
+          - Kind:            S_END
+            ScopeEndSym:     
+          - Kind:            S_BLOCK32
+            BlockSym:        
+              CodeSize:        17
+              Offset:          34
+              BlockName:       ''
+          - Kind:            S_REGREL32
+            RegRelativeSym:  
+              Offset:          36
+              Type:            116
+              Register:        RSP
+              VarName:         y
+          - Kind:            S_END
+            ScopeEndSym:     
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        58
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\a.c'
+            Lines:           
+              - Offset:          0
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          8
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          15
+                LineStart:       5
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          23
+                LineStart:       6
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          32
+                LineStart:       7
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          34
+                LineStart:       8
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          42
+                LineStart:       9
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          51
+                LineStart:       11
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+      - !FileChecksums
+        Checksums:       
+          - FileName:        'c:\src\llvm-project\build\a.c'
+            Kind:            MD5
+            Checksum:        7FA72225C3F5630316383BD8BCC3EF72
+      - !StringTable
+        Strings:         
+          - 'c:\src\llvm-project\build\a.c'
+      - !Symbols
+        Records:         
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:    
+              BuildId:         4110
+    Relocations:     
+      - VirtualAddress:  152
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  156
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  220
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  224
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  292
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  296
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  369
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  373
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  412
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  416
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  452
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  456
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:           
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [ 116 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  1
+          ArgumentList:    4096
+      - Kind:            LF_POINTER
+        Pointer:         
+          ReferentType:    4097
+          Attrs:           65548
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            g
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  1
+          ArgumentList:    4096
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4100
+          Name:            main
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            f
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:      
+          StringIndices:   [ 4105 ]
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              4106
+          String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          a.c
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:       
+          ArgIndices:      [ 4103, 4104, 4108, 4109, 4107 ]
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     894C2408C3CCCCCCCCCCCCCCCCCCCCCC894C24084883EC38837C2440007413C74424202A0000008B4C2420E800000000EB11C74424240D0000008B4C2424E80000000033C04883C438C3
+    Relocations:     
+      - VirtualAddress:  44
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  63
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0108010008620000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000003A00000000000000
+    Relocations:     
+      - VirtualAddress:  0
+        SymbolName:      '$LN5'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN5'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$main'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:         
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          628
+      NumberOfRelocations: 12
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          624
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          74
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        2120072435
+      Number:          0
+  - Name:            g
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            f
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           16
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN5'
+    Value:           16
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        3137252093
+      Number:          0
+  - Name:            '$unwind$main'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        336416693
+      Number:          0
+  - Name:            '$pdata$main'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb-scopes-b.yaml b/test/COFF/Inputs/pdb-scopes-b.yaml
new file mode 100644 (file)
index 0000000..2839bf7
--- /dev/null
@@ -0,0 +1,365 @@
+--- !COFF
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:        
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_OBJNAME
+            ObjNameSym:      
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\b.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:     
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              CodeSize:        62
+              DbgStart:        8
+              DbgEnd:          57
+              FunctionType:    4101
+              Flags:           [  ]
+              DisplayName:     f
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 56
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_REGREL32
+            RegRelativeSym:  
+              Offset:          64
+              Type:            116
+              Register:        RSP
+              VarName:         x
+          - Kind:            S_BLOCK32
+            BlockSym:        
+              CodeSize:        20
+              Offset:          15
+              BlockName:       ''
+          - Kind:            S_REGREL32
+            RegRelativeSym:  
+              Offset:          32
+              Type:            116
+              Register:        RSP
+              VarName:         y
+          - Kind:            S_END
+            ScopeEndSym:     
+          - Kind:            S_BLOCK32
+            BlockSym:        
+              CodeSize:        20
+              Offset:          37
+              BlockName:       ''
+          - Kind:            S_REGREL32
+            RegRelativeSym:  
+              Offset:          36
+              Type:            116
+              Register:        RSP
+              VarName:         w
+          - Kind:            S_END
+            ScopeEndSym:     
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        62
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\b.c'
+            Lines:           
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          8
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          15
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          26
+                LineStart:       5
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          35
+                LineStart:       6
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          37
+                LineStart:       7
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          48
+                LineStart:       8
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          57
+                LineStart:       10
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+      - !FileChecksums
+        Checksums:       
+          - FileName:        'c:\src\llvm-project\build\b.c'
+            Kind:            MD5
+            Checksum:        8E8C92DB46478902EBEAEBFCFF15A6E0
+      - !StringTable
+        Strings:         
+          - 'c:\src\llvm-project\build\b.c'
+      - !Symbols
+        Records:         
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:    
+              BuildId:         4110
+    Relocations:     
+      - VirtualAddress:  152
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  156
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  223
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  227
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  266
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  270
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  308
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  312
+        SymbolName:      f
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:           
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_POINTER
+        Pointer:         
+          ReferentType:    4097
+          Attrs:           65548
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [ 116 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  1
+          ArgumentList:    4099
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4100
+          Name:            f
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            g
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:      
+          StringIndices:   [ 4105 ]
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              4106
+          String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          b.c
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:       
+          ArgIndices:      [ 4103, 4104, 4108, 4109, 4107 ]
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     894C24084883EC38837C24400074168B44244083C003894424208B4C2420E800000000EB148B44244083C004894424248B4C2424E8000000004883C438C3
+    Relocations:     
+      - VirtualAddress:  31
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  53
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0108010008620000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '000000003E00000000000000'
+    Relocations:     
+      - VirtualAddress:  0
+        SymbolName:      '$LN5'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN5'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$f'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:         
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          484
+      NumberOfRelocations: 8
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          616
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          62
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        3841032836
+      Number:          0
+  - Name:            g
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            f
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN5'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        3137252093
+      Number:          0
+  - Name:            '$unwind$f'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        2420588879
+      Number:          0
+  - Name:            '$pdata$f'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb-type-server-simple-a.yaml b/test/COFF/Inputs/pdb-type-server-simple-a.yaml
new file mode 100644 (file)
index 0000000..78c6816
--- /dev/null
@@ -0,0 +1,255 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\a.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              CodeSize:        27
+              DbgStart:        4
+              DbgEnd:          22
+              FunctionType:    4098
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 56
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_REGREL32
+            RegRelativeSym:
+              Offset:          32
+              Type:            4102
+              Register:        RSP
+              VarName:         f
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        27
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'c:\src\llvm-project\build\a.c'
+            Lines:
+              - Offset:          0
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          4
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          12
+                LineStart:       5
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          22
+                LineStart:       6
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !Symbols
+        Records:
+          - Kind:            S_UDT
+            UDTSym:
+              Type:            4102
+              UDTName:         Foo
+      - !FileChecksums
+        Checksums:
+          - FileName:        'c:\src\llvm-project\build\a.c'
+            Kind:            MD5
+            Checksum:        BF69E7E933074E1B7ED1FE8FB395965B
+      - !StringTable
+        Strings:
+          - 'c:\src\llvm-project\build\a.c'
+      - !Symbols
+        Records:
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:
+              BuildId:         4107
+    Relocations:
+      - VirtualAddress:  152
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  156
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  224
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  228
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:
+      - Kind:            LF_TYPESERVER2
+        TypeServer2:
+          Guid:            '{41414141-4141-4141-4141-414141414141}'
+          Age:             1
+          Name:            'C:\src\llvm-project\build\ts.pdb'
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC38C74424202A000000488D4C2420E8000000004883C438C3
+    Relocations:
+      - VirtualAddress:  18
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0104010004620000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000001B00000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$main'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          388
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          64
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          27
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1939996292
+      Number:          0
+  - Name:            g
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN3'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        931692337
+      Number:          0
+  - Name:            '$unwind$main'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        567356797
+      Number:          0
+  - Name:            '$pdata$main'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb-type-server-simple-b.yaml b/test/COFF/Inputs/pdb-type-server-simple-b.yaml
new file mode 100644 (file)
index 0000000..56e97d5
--- /dev/null
@@ -0,0 +1,173 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\b.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              CodeSize:        13
+              DbgStart:        5
+              DbgEnd:          12
+              FunctionType:    4099
+              Flags:           [  ]
+              DisplayName:     g
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_REGREL32
+            RegRelativeSym:
+              Offset:          8
+              Type:            4097
+              Register:        RSP
+              VarName:         p
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        13
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'c:\src\llvm-project\build\b.c'
+            Lines:
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !Symbols
+        Records:
+          - Kind:            S_UDT
+            UDTSym:
+              Type:            4102
+              UDTName:         Foo
+      - !FileChecksums
+        Checksums:
+          - FileName:        'c:\src\llvm-project\build\b.c'
+            Kind:            MD5
+            Checksum:        DDF8FD35CD67990C5D4147516BE10D0C
+      - !StringTable
+        Strings:
+          - 'c:\src\llvm-project\build\b.c'
+      - !Symbols
+        Records:
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:
+              BuildId:         4111
+    Relocations:
+      - VirtualAddress:  152
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  156
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  220
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  224
+        SymbolName:      g
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:
+      - Kind:            LF_TYPESERVER2
+        TypeServer2:
+          Guid:            '{41414141-4141-4141-4141-414141414141}'
+          Age:             1
+          Name:            'C:\src\llvm-project\build\ts.pdb'
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     48894C2408488B4424088B00C3
+symbols:
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          360
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          64
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          13
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        3246683207
+      Number:          0
+  - Name:            g
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/pdb-type-server-simple-ts.yaml b/test/COFF/Inputs/pdb-type-server-simple-ts.yaml
new file mode 100644 (file)
index 0000000..7349657
--- /dev/null
@@ -0,0 +1,147 @@
+---
+MSF:
+  SuperBlock:
+    BlockSize:       4096
+    FreeBlockMap:    1
+    NumBlocks:       19
+    NumDirectoryBytes: 64
+    Unknown1:        0
+    BlockMapAddr:    17
+  NumDirectoryBlocks: 1
+  DirectoryBlocks: [ 16 ]
+  NumStreams:      0
+  FileSize:        77824
+PdbStream:
+  Age:             1
+  Guid:            '{41414141-4141-4141-4141-414141414141}'
+  Signature:       1500053944
+  Features:        [ VC140 ]
+  Version:         VC70
+TpiStream:
+  Version:         VC80
+  Records:
+    - Kind:            LF_STRUCTURE
+      Class:
+        MemberCount:     0
+        Options:         [ None, ForwardReference, HasUniqueName ]
+        FieldList:       0
+        Name:            Foo
+        UniqueName:      '.?AUFoo@@'
+        DerivationList:  0
+        VTableShape:     0
+        Size:            0
+    - Kind:            LF_POINTER
+      Pointer:
+        ReferentType:    4096
+        Attrs:           65548
+    - Kind:            LF_ARGLIST
+      ArgList:
+        ArgIndices:      [ 4097 ]
+    - Kind:            LF_PROCEDURE
+      Procedure:
+        ReturnType:      116
+        CallConv:        NearC
+        Options:         [ None ]
+        ParameterCount:  1
+        ArgumentList:    4098
+    - Kind:            LF_POINTER
+      Pointer:
+        ReferentType:    4099
+        Attrs:           65548
+    - Kind:            LF_FIELDLIST
+      FieldList:
+        - Kind:            LF_MEMBER
+          DataMember:
+            Attrs:           3
+            Type:            116
+            FieldOffset:     0
+            Name:            x
+    - Kind:            LF_STRUCTURE
+      Class:
+        MemberCount:     1
+        Options:         [ None, HasUniqueName ]
+        FieldList:       4101
+        Name:            Foo
+        UniqueName:      '.?AUFoo@@'
+        DerivationList:  0
+        VTableShape:     0
+        Size:            4
+    - Kind:            LF_ARGLIST
+      ArgList:
+        ArgIndices:      [ 0 ]
+    - Kind:            LF_PROCEDURE
+      Procedure:
+        ReturnType:      116
+        CallConv:        NearC
+        Options:         [ None ]
+        ParameterCount:  0
+        ArgumentList:    4103
+IpiStream:
+  Version:         VC80
+  Records:
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          'c:\src\llvm-project\build\a.c'
+    - Kind:            LF_UDT_SRC_LINE
+      UdtSourceLine:
+        UDT:             4102
+        SourceFile:      4096
+        LineNumber:      1
+    - Kind:            LF_FUNC_ID
+      FuncId:
+        ParentScope:     0
+        FunctionType:    4104
+        Name:            main
+    - Kind:            LF_FUNC_ID
+      FuncId:
+        ParentScope:     0
+        FunctionType:    4099
+        Name:            g
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          'C:\src\llvm-project\build'
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          '-c -Zi -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+    - Kind:            LF_SUBSTR_LIST
+      StringList:
+        StringIndices:   [ 4102 ]
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              4103
+        String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          a.c
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          'C:\src\llvm-project\build\ts.pdb'
+    - Kind:            LF_BUILDINFO
+      BuildInfo:
+        ArgIndices:      [ 4100, 4101, 4105, 4106, 4104 ]
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          'c:\src\llvm-project\build\b.c'
+    - Kind:            LF_UDT_SRC_LINE
+      UdtSourceLine:
+        UDT:             4102
+        SourceFile:      4108
+        LineNumber:      1
+    - Kind:            LF_STRING_ID
+      StringId:
+        Id:              0
+        String:          b.c
+    - Kind:            LF_BUILDINFO
+      BuildInfo:
+        ArgIndices:      [ 4100, 4101, 4110, 4106, 4104 ]
+...
diff --git a/test/COFF/Inputs/pdb1.yaml b/test/COFF/Inputs/pdb1.yaml
new file mode 100644 (file)
index 0000000..90905ae
--- /dev/null
@@ -0,0 +1,302 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'D:\b\ret42-main.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   23026
+              FrontendQFE:     0
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    23026
+              BackendQFE:      0
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              CodeSize:        14
+              DbgStart:        4
+              DbgEnd:          9
+              FunctionType:    4101
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 40
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        14
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'd:\b\ret42-main.c'
+            Lines:
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !FileChecksums
+        Checksums:
+          - FileName:        'd:\b\ret42-main.c'
+            Kind:            MD5
+            Checksum:        C538722F63570DF6705DDE06FE96E5D1
+      - !StringTable
+        Strings:
+          - 'd:\b\ret42-main.c'
+      - !Symbols
+        Records:
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:
+              BuildId:         4110
+    Relocations:
+      - VirtualAddress:  140
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  144
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  196
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  200
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_POINTER
+        Pointer:
+          ReferentType:    4097
+          Attrs:           65548
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4099
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4100
+          Name:            main
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            foo
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'C:\vs14\VC\BIN\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:
+          StringIndices:   [ 4105 ]
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              4106
+          String:          ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          ret42-main.c
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:
+          ArgIndices:      [ 4103, 4104, 4108, 4109, 4107 ]
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0104010004420000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '000000000E00000000000000'
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$main'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            '@comp.id'
+    Value:           17062386
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           2147484048
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          304
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          636
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+  - Name:            foo
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN3'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        264583633
+      Number:          0
+  - Name:            '$unwind$main'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        361370162
+      Number:          0
+  - Name:            '$pdata$main'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb2.yaml b/test/COFF/Inputs/pdb2.yaml
new file mode 100644 (file)
index 0000000..6507951
--- /dev/null
@@ -0,0 +1,217 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'D:\b\ret42-sub.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   23026
+              FrontendQFE:     0
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    23026
+              BackendQFE:      0
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        6
+              DbgStart:        0
+              DbgEnd:          5
+              FunctionType:    4098
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     foo
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        6
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'd:\b\ret42-sub.c'
+            Lines:
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !FileChecksums
+        Checksums:
+          - FileName:        'd:\b\ret42-sub.c'
+            Kind:            MD5
+            Checksum:        EC2D89EFF5A1FEB6B74EE4D79074072F
+      - !StringTable
+        Strings:
+          - 'd:\b\ret42-sub.c'
+      - !Symbols
+        Records:
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:
+              BuildId:         4106
+    Relocations:
+      - VirtualAddress:  140
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  144
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  196
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  200
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            foo
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'C:\vs14\VC\BIN\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:
+          StringIndices:   [ 4101 ]
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              4102
+          String:          ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          ret42-sub.c
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'D:\b\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:
+          ArgIndices:      [ 4099, 4100, 4104, 4105, 4103 ]
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            '@comp.id'
+    Value:           17062386
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           2147484048
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          304
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          572
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        2139436471
+      Number:          0
+  - Name:            foo
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/pdb_comdat_bar.yaml b/test/COFF/Inputs/pdb_comdat_bar.yaml
new file mode 100644 (file)
index 0000000..71a9535
--- /dev/null
@@ -0,0 +1,440 @@
+--- !COFF
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:        
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_OBJNAME
+            ObjNameSym:      
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\pdb_comdat_bar.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:     
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        14
+              DbgStart:        4
+              DbgEnd:          9
+              FunctionType:    4102
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     bar
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 40
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        14
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\pdb_comdat_bar.c'
+            Lines:           
+              - Offset:          0
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          4
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          9
+                LineStart:       5
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+      - !Symbols
+        Records:         
+          - Kind:            S_GDATA32
+            DataSym:         
+              Type:            116
+              DisplayName:     global
+      - !FileChecksums
+        Checksums:       
+          - FileName:        'c:\src\llvm-project\build\pdb_comdat_bar.c'
+            Kind:            MD5
+            Checksum:        365279DB4FCBEDD721BBFC3B14A953C2
+          - FileName:        'c:\src\llvm-project\build\foo.h'
+            Kind:            MD5
+            Checksum:        D74D834EFAC3AE2B45E606A8320B1D5C
+      - !StringTable
+        Strings:         
+          - 'c:\src\llvm-project\build\pdb_comdat_bar.c'
+          - 'c:\src\llvm-project\build\foo.h'
+      - !Symbols
+        Records:         
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:    
+              BuildId:         4110
+    Relocations:     
+      - VirtualAddress:  168
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  172
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  224
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  228
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  288
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  292
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:           
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_POINTER
+        Pointer:         
+          ReferentType:    4097
+          Attrs:           65548
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            foo
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4100
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4101
+          Name:            bar
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:      
+          StringIndices:   [ 4105 ]
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              4106
+          String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          pdb_comdat_bar.c
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:       
+          ArgIndices:      [ 4103, 4104, 4108, 4109, 4107 ]
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:     
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     8B0500000000FFC0890500000000C3
+    Relocations:     
+      - VirtualAddress:  2
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  10
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        15
+              DbgStart:        0
+              DbgEnd:          14
+              FunctionType:    4099
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     foo
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ MarkedInline, AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        15
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\foo.h'
+            Lines:           
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          0
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          14
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+    Relocations:     
+      - VirtualAddress:  44
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  48
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  100
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  104
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0104010004420000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '000000000E00000000000000'
+    Relocations:     
+      - VirtualAddress:  0
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$bar'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:         
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          460
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          628
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            global
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          15
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        1746394828
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          148
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          6
+      Selection:       IMAGE_COMDAT_SELECT_ASSOCIATIVE
+  - Name:            foo
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN3'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        264583633
+      Number:          0
+  - Name:            '$unwind$bar'
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        361370162
+      Number:          0
+  - Name:            '$pdata$bar'
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb_comdat_main.yaml b/test/COFF/Inputs/pdb_comdat_main.yaml
new file mode 100644 (file)
index 0000000..d9019d6
--- /dev/null
@@ -0,0 +1,446 @@
+--- !COFF
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:        
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_OBJNAME
+            ObjNameSym:      
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\pdb_comdat_main.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:     
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        24
+              DbgStart:        4
+              DbgEnd:          19
+              FunctionType:    4102
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 40
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        24
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\pdb_comdat_main.c'
+            Lines:           
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          4
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          9
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          14
+                LineStart:       5
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          19
+                LineStart:       6
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+      - !Symbols
+        Records:         
+          - Kind:            S_GDATA32
+            DataSym:         
+              Type:            116
+              DisplayName:     global
+      - !FileChecksums
+        Checksums:       
+          - FileName:        'c:\src\llvm-project\build\pdb_comdat_main.c'
+            Kind:            MD5
+            Checksum:        F969E51BBE373436D81492EB61387F36
+          - FileName:        'c:\src\llvm-project\build\foo.h'
+            Kind:            MD5
+            Checksum:        D74D834EFAC3AE2B45E606A8320B1D5C
+      - !StringTable
+        Strings:         
+          - 'c:\src\llvm-project\build\pdb_comdat_main.c'
+          - 'c:\src\llvm-project\build\foo.h'
+      - !Symbols
+        Records:         
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:    
+              BuildId:         4111
+    Relocations:     
+      - VirtualAddress:  168
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  172
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  224
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  228
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  304
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  308
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:           
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_POINTER
+        Pointer:         
+          ReferentType:    4097
+          Attrs:           65548
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            foo
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4100
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4101
+          Name:            main
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            bar
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:      
+          StringIndices:   [ 4106 ]
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              4107
+          String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          pdb_comdat_main.c
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:       
+          ArgIndices:      [ 4104, 4105, 4109, 4110, 4108 ]
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E800000000E800000000B82A0000004883C428C3
+    Relocations:     
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  10
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     8B0500000000FFC0890500000000C3
+    Relocations:     
+      - VirtualAddress:  2
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  10
+        SymbolName:      global
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        15
+              DbgStart:        0
+              DbgEnd:          14
+              FunctionType:    4099
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     foo
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ MarkedInline, AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        15
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\foo.h'
+            Lines:           
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          0
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          14
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+    Relocations:     
+      - VirtualAddress:  44
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  48
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  100
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  104
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0104010004420000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '000000001800000000000000'
+    Relocations:     
+      - VirtualAddress:  0
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$main'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:         
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          480
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          648
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          24
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        492663294
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          15
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        1746394828
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          148
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          5
+      Selection:       IMAGE_COMDAT_SELECT_ASSOCIATIVE
+  - Name:            foo
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN3'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        264583633
+      Number:          0
+  - Name:            '$unwind$main'
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        2942184094
+      Number:          0
+  - Name:            '$pdata$main'
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            global
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/pdb_lines_1.yaml b/test/COFF/Inputs/pdb_lines_1.yaml
new file mode 100644 (file)
index 0000000..3fbb2a9
--- /dev/null
@@ -0,0 +1,480 @@
+--- !COFF
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:        
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_OBJNAME
+            ObjNameSym:      
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\pdb_lines_1.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:     
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        19
+              DbgStart:        4
+              DbgEnd:          14
+              FunctionType:    4102
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 40
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        19
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\pdb_lines_1.c'
+            Lines:           
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          4
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          9
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          14
+                LineStart:       5
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+      - !FileChecksums
+        Checksums:       
+          - FileName:        'c:\src\llvm-project\build\pdb_lines_1.c'
+            Kind:            MD5
+            Checksum:        4EB19DCD86C3BA2238A255C718572E7B
+          - FileName:        'c:\src\llvm-project\build\foo.h'
+            Kind:            MD5
+            Checksum:        061EB73ABB642532857A4F1D9CBAC323
+      - !StringTable
+        Strings:         
+          - 'c:\src\llvm-project\build\pdb_lines_1.c'
+          - 'c:\src\llvm-project\build\foo.h'
+      - !Symbols
+        Records:         
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:    
+              BuildId:         4111
+    Relocations:     
+      - VirtualAddress:  164
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  168
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  220
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  224
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:           
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_POINTER
+        Pointer:         
+          ReferentType:    4097
+          Attrs:           65548
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            foo
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4100
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4101
+          Name:            main
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            bar
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:      
+          StringIndices:   [ 4106 ]
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              4107
+          String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          pdb_lines_1.c
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:       
+          ArgIndices:      [ 4104, 4105, 4109, 4110, 4108 ]
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E800000000B82A0000004883C428C3
+    Relocations:     
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:     
+      - VirtualAddress:  5
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        14
+              DbgStart:        4
+              DbgEnd:          9
+              FunctionType:    4099
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     foo
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 40
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ MarkedInline, AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        14
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\foo.h'
+            Lines:           
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          4
+                LineStart:       3
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          9
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+    Relocations:     
+      - VirtualAddress:  44
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  48
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  100
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  104
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0104010004420000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '000000000E00000000000000'
+    Relocations:     
+      - VirtualAddress:  0
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$foo'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '0104010004420000'
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '000000001300000000000000'
+    Relocations:     
+      - VirtualAddress:  0
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      '$LN3'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      '$unwind$main'
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:         
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          432
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          644
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          19
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        791570821
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          148
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          5
+      Selection:       IMAGE_COMDAT_SELECT_ASSOCIATIVE
+  - Name:            bar
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            foo
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN3'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            '$LN3'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        264583633
+      Number:          5
+      Selection:       IMAGE_COMDAT_SELECT_ASSOCIATIVE
+  - Name:            '$unwind$foo'
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        361370162
+      Number:          5
+      Selection:       IMAGE_COMDAT_SELECT_ASSOCIATIVE
+  - Name:            '$pdata$foo'
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        264583633
+      Number:          0
+  - Name:            '$unwind$main'
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   10
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        4063508168
+      Number:          0
+  - Name:            '$pdata$main'
+    Value:           0
+    SectionNumber:   10
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/Inputs/pdb_lines_2.yaml b/test/COFF/Inputs/pdb_lines_2.yaml
new file mode 100644 (file)
index 0000000..8ad8d06
--- /dev/null
@@ -0,0 +1,209 @@
+--- !COFF
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:        
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:     
+      - !Symbols
+        Records:         
+          - Kind:            S_OBJNAME
+            ObjNameSym:      
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\pdb_lines_2.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:     
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:         
+          - Kind:            S_GPROC32_ID
+            ProcSym:         
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        1
+              DbgStart:        0
+              DbgEnd:          0
+              FunctionType:    4098
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     bar
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:    
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:     
+      - !Lines
+        CodeSize:        1
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:          
+          - FileName:        'c:\src\llvm-project\build\pdb_lines_2.c'
+            Lines:           
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          0
+                LineStart:       2
+                IsStatement:     true
+                EndDelta:        0
+            Columns:         
+      - !FileChecksums
+        Checksums:       
+          - FileName:        'c:\src\llvm-project\build\pdb_lines_2.c'
+            Kind:            MD5
+            Checksum:        DF91CB3A2B8D917486574BB50CAC4CC7
+      - !StringTable
+        Strings:         
+          - 'c:\src\llvm-project\build\pdb_lines_2.c'
+      - !Symbols
+        Records:         
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:    
+              BuildId:         4106
+    Relocations:     
+      - VirtualAddress:  164
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  168
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  220
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  224
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:           
+      - Kind:            LF_ARGLIST
+        ArgList:         
+          ArgIndices:      [  ]
+      - Kind:            LF_PROCEDURE
+        Procedure:       
+          ReturnType:      3
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_FUNC_ID
+        FuncId:          
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            bar
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:      
+          StringIndices:   [ 4101 ]
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              4102
+          String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          pdb_lines_2.c
+      - Kind:            LF_STRING_ID
+        StringId:        
+          Id:              0
+          String:          'C:\src\llvm-project\build\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:       
+          ArgIndices:      [ 4099, 4100, 4104, 4105, 4103 ]
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     C3
+symbols:         
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          360
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          568
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition: 
+      Length:          1
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        40735498
+      Number:          0
+  - Name:            bar
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/resource.res b/test/COFF/Inputs/resource.res
new file mode 100644 (file)
index 0000000..f1c799f
Binary files /dev/null and b/test/COFF/Inputs/resource.res differ
diff --git a/test/COFF/Inputs/ret42.lib b/test/COFF/Inputs/ret42.lib
new file mode 100644 (file)
index 0000000..f60a9cd
Binary files /dev/null and b/test/COFF/Inputs/ret42.lib differ
diff --git a/test/COFF/Inputs/ret42.obj b/test/COFF/Inputs/ret42.obj
new file mode 100644 (file)
index 0000000..1765f0e
Binary files /dev/null and b/test/COFF/Inputs/ret42.obj differ
diff --git a/test/COFF/Inputs/ret42.yaml b/test/COFF/Inputs/ret42.yaml
new file mode 100644 (file)
index 0000000..b980901
--- /dev/null
@@ -0,0 +1,45 @@
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     B82A000000C3
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       16
+    SectionData:     ''
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/std32.lib b/test/COFF/Inputs/std32.lib
new file mode 100644 (file)
index 0000000..7401ff3
Binary files /dev/null and b/test/COFF/Inputs/std32.lib differ
diff --git a/test/COFF/Inputs/std64.lib b/test/COFF/Inputs/std64.lib
new file mode 100644 (file)
index 0000000..bbd223c
Binary files /dev/null and b/test/COFF/Inputs/std64.lib differ
diff --git a/test/COFF/Inputs/thinlto-mangled-qux.ll b/test/COFF/Inputs/thinlto-mangled-qux.ll
new file mode 100644 (file)
index 0000000..4c9cc8e
--- /dev/null
@@ -0,0 +1,28 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.0.24215"
+
+%class.baz = type { %class.bar }
+%class.bar = type { i32 (...)** }
+
+$"\01?x@bar@@UEBA_NXZ" = comdat any
+
+$"\01??_7baz@@6B@" = comdat any
+
+$"\01??_Gbaz@@UEAAPEAXI@Z" = comdat any
+
+@"\01??_7baz@@6B@" = linkonce_odr unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (i8* (%class.baz*, i32)* @"\01??_Gbaz@@UEAAPEAXI@Z" to i8*), i8* bitcast (i1 (%class.bar*)* @"\01?x@bar@@UEBA_NXZ" to i8*)] }, comdat, !type !0, !type !1
+
+define void @"\01?qux@@YAXXZ"() local_unnamed_addr {
+  ret void
+}
+
+define linkonce_odr i8* @"\01??_Gbaz@@UEAAPEAXI@Z"(%class.baz* %this, i32 %should_call_delete) unnamed_addr comdat {
+  ret i8* null
+}
+
+define linkonce_odr zeroext i1 @"\01?x@bar@@UEBA_NXZ"(%class.bar* %this) unnamed_addr comdat {
+  ret i1 false
+}
+
+!0 = !{i64 0, !"?AVbar@@"}
+!1 = !{i64 0, !"?AVbaz@@"}
diff --git a/test/COFF/Inputs/weak-external.ll b/test/COFF/Inputs/weak-external.ll
new file mode 100644 (file)
index 0000000..4775d50
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @g() {
+  ret void
+}
diff --git a/test/COFF/Inputs/weak-external2.ll b/test/COFF/Inputs/weak-external2.ll
new file mode 100644 (file)
index 0000000..2102c3b
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @f() {
+  ret void
+}
diff --git a/test/COFF/Inputs/weak-external3.ll b/test/COFF/Inputs/weak-external3.ll
new file mode 100644 (file)
index 0000000..f9a5136
--- /dev/null
@@ -0,0 +1,8 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+@f = weak alias void(), void()* @g
+
+define void @g() {
+  ret void
+}
diff --git a/test/COFF/alternatename.test b/test/COFF/alternatename.test
new file mode 100644 (file)
index 0000000..1be61ad
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /entry:foo /subsystem:console \
+# RUN:   /alternatename:foo=main /out:%t.exe %t.obj
+# RUN: lld-link /entry:foo /subsystem:console \
+# RUN:   /alternatename:foo=main \
+# RUN:   /alternatename:foo=main \
+# RUN:   /alternatename:nosuchsym1=nosuchsym2 \
+# RUN:   /out:%t.exe %t.obj
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /subsystem:console /out:%t.exe %t.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     B82A000000C3
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       16
+    SectionData:     ''
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f616c7465726e6174656e616d653a666f6f3d6d61696e00  # /alternatename:foo=main
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/ar-comdat.test b/test/COFF/ar-comdat.test
new file mode 100644 (file)
index 0000000..5420b5b
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: yaml2obj %s > %t1.obj
+# RUN: yaml2obj %s > %t2.obj
+# RUN: llvm-lib /out:%t.lib %t1.obj %t2.obj
+# RUN: lld-link /out:%t.exe /lldmap:%t.map /entry:main /subsystem:console %p/Inputs/ret42.obj %t.lib
+# RUN: FileCheck %s < %t.map
+
+# CHECK-NOT: .lib
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+symbols:
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            x
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/arm-thumb-branch-error.s b/test/COFF/arm-thumb-branch-error.s
new file mode 100644 (file)
index 0000000..00b835c
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: not lld-link -entry:_start -subsystem:console %t %tfar -out:%t2 2>&1 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .globl _start
+_start:
+ bl  too_far1
+
+// CHECK: relocation out of range
diff --git a/test/COFF/arm64-magic.yaml b/test/COFF/arm64-magic.yaml
new file mode 100644 (file)
index 0000000..a35eeca
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: Format: COFF-ARM64
+# CHECK: Arch: aarch64
+# CHECK: AddressSize: 64bit
+# CHECK: ImageFileHeader {
+# CHECK:   Machine: IMAGE_FILE_MACHINE_ARM64 (0xAA64)
+# CHECK:   Characteristics [ (0x22)
+# CHECK:     IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
+# CHECK:     IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20)
+# CHECK:   ]
+# CHECK: }
+# CHECK: ImageOptionalHeader {
+# CHECK:   Magic: 0x20B
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARM64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     'e0031f2ac0035fd6'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            mainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/arm64-relocs-imports.test b/test/COFF/arm64-relocs-imports.test
new file mode 100644 (file)
index 0000000..3d252aa
--- /dev/null
@@ -0,0 +1,136 @@
+# REQUIRES: aarch64
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0:       fe 0f 1f f8     str     x30, [sp, #-16]!
+# BEFORE:        4:       00 00 00 90     adrp    x0, #0
+# BEFORE:        8:       00 08 00 91     add     x0, x0, #2
+# BEFORE:        c:       00 00 00 94     bl      #0
+# BEFORE:       10:       00 01 40 39     ldrb    w0, [x8]
+# BEFORE:       14:       00 01 40 79     ldrh    w0, [x8]
+# BEFORE:       18:       00 01 40 b9     ldr     w0, [x8]
+# BEFORE:       1c:       00 01 40 f9     ldr     x0, [x8]
+# BEFORE:       20:       e0 03 1f 2a     mov      w0, wzr
+# BEFORE:       24:       fe 07 41 f8     ldr     x30, [sp], #16
+# BEFORE:       28:       c0 03 5f d6     ret
+# BEFORE:       2c:       08 00 00 00     <unknown>
+# BEFORE:       30:       00 00 00 00     <unknown>
+
+# AFTER: Disassembly of section .text:
+# AFTER:  140002000:      fe 0f 1f f8     str     x30, [sp, #-16]!
+# AFTER:  140002004:      e0 ff ff f0     adrp    x0, #-4096
+# AFTER:  140002008:      00 18 00 91     add     x0, x0, #6
+# AFTER:  14000200c:      0a 00 00 94     bl      #40
+# AFTER:  140002010:      00 21 40 39     ldrb    w0, [x8, #8]
+# AFTER:  140002014:      00 11 40 79     ldrh    w0, [x8, #8]
+# AFTER:  140002018:      00 09 40 b9     ldr     w0, [x8, #8]
+# AFTER:  14000201c:      00 05 40 f9     ldr     x0, [x8, #8]
+# AFTER:  140002020:      e0 03 1f 2a     mov      w0, wzr
+# AFTER:  140002024:      fe 07 41 f8     ldr     x30, [sp], #16
+# AFTER:  140002028:      c0 03 5f d6     ret
+# AFTER:  14000202c:      10 10 00 40     <unknown>
+# AFTER:  140002030:      01 00 00 00     <unknown>
+# AFTER:  140002034:      10 00 00 b0     adrp    x16, #4096
+# AFTER:  140002038:      10 1e 40 f9     ldr     x16, [x16, #56]
+# AFTER:  14000203c:      00 02 1f d6     br      x16
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARM64
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     FE0F1FF80000009000080091000000940001403900014079000140B9000140F9E0031F2AFE0741F8C0035FD60800000000000000
+    Relocations:
+      - VirtualAddress:  4
+        SymbolName:      .Lstr
+        Type:            4
+      - VirtualAddress:  8
+        SymbolName:      .Lstr
+        Type:            6
+      - VirtualAddress:  12
+        SymbolName:      function
+        Type:            3
+      - VirtualAddress:  16
+        SymbolName:      .Lglobal
+        Type:            7
+      - VirtualAddress:  20
+        SymbolName:      .Lglobal
+        Type:            7
+      - VirtualAddress:  24
+        SymbolName:      .Lglobal
+        Type:            7
+      - VirtualAddress:  28
+        SymbolName:      .Lglobal
+        Type:            7
+      - VirtualAddress:  44
+        SymbolName:      .Lglobal
+        Type:            14
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     00000000202068656C6C6F20776F726C6400
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        1438860354
+      Number:          1
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          12
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        872944732
+      Number:          4
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            .Lstr
+    Value:           4
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .Lglobal
+    Value:           8
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            function
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-blx23t.test b/test/COFF/armnt-blx23t.test
new file mode 100644 (file)
index 0000000..5caf6eb
--- /dev/null
@@ -0,0 +1,66 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /entry:function /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 70 47         bx lr
+# BEFORE:        2: 00 bf         nop
+# BEFORE:        4: 2d e9 00 48   push.w {r11, lr}
+# BEFORE:        8: eb 46         mov r11, sp
+# BEFORE:        a: 20 20         movs r0, #32
+# BEFORE:        c: 00 f0 00 f8   bl #0
+# BEFORE:       10: 01 30         adds r0, #1
+# BEFORE:       12: bd e8 00 88   pop.w {r11, pc}
+
+# AFTER: Disassembly of section .text:
+# AFTER:     1000: 70 47         bx lr
+# AFTER:     1002: 00 bf         nop
+# AFTER:     1004: 2d e9 00 48   push.w {r11, lr}
+# AFTER:     1008: eb 46         mov r11, sp
+# AFTER:     100a: 20 20         movs r0, #32
+# AFTER:     100c: ff f7 f8 ff   bl #-16
+# AFTER:     1010: 01 30         adds r0, #1
+# AFTER:     1012: bd e8 00 88   pop.w {r11, pc}
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     704700BF2DE90048EB46202000F000F80130BDE80088
+    Relocations:
+      - VirtualAddress:  12
+        SymbolName:      identity
+        Type:            21
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          22
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            identity
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            function
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-branch24t.test b/test/COFF/armnt-branch24t.test
new file mode 100644 (file)
index 0000000..6e1114c
--- /dev/null
@@ -0,0 +1,59 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /entry:function /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 70 47         bx lr
+# BEFORE:        2: 00 bf         nop
+# BEFORE:        4: 20 20         movs r0, #32
+# BEFORE:        6: 00 f0 00 b8   b.w #0
+
+# AFTER: Disassembly of section .text:
+# AFTER: .text:
+# AFTER:     1000: 70 47         bx lr
+# AFTER:     1002: 00 bf         nop
+# AFTER:     1004: 20 20         movs r0, #32
+# AFTER:     1006: ff f7 fb bf   b.w #-10
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     704700BF202000F000B8
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      identity
+        Type:            20
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          10
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            identity
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            function
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-entry-point.test b/test/COFF/armnt-entry-point.test
new file mode 100644 (file)
index 0000000..7b1bd10
--- /dev/null
@@ -0,0 +1,5 @@
+# RUN: yaml2obj < %p/Inputs/armnt-executable.obj.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: AddressOfEntryPoint: 0x1001
diff --git a/test/COFF/armnt-imports.test b/test/COFF/armnt-imports.test
new file mode 100644 (file)
index 0000000..519886e
--- /dev/null
@@ -0,0 +1,51 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /subsystem:console %t.obj \
+# RUN:   /entry:mainCRTStartup %p/Inputs/library.lib
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
+
+# CHECK: Import {
+# CHECK:   Name: library.dll
+# CHECK:   ImportLookupTableRVA: 0x2028
+# CHECK:   ImportAddressTableRVA: 0x2030
+# CHECK:   Symbol: function (0)
+# CHECK: }
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     40F20000C0F2000000680047
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __imp_function
+        Type:            17
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          12
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            mainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp_function
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-mov32t-exec.test b/test/COFF/armnt-mov32t-exec.test
new file mode 100644 (file)
index 0000000..629f062
--- /dev/null
@@ -0,0 +1,60 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /out:%t.exe /subsystem:console /entry:get_function %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 70 47         bx lr
+# BEFORE:        2: 00 bf         nop
+# BEFORE:        4: 40 f2 00 00   movw r0, #0
+# BEFORE:        8: c0 f2 00 00   movt r0, #0
+# BEFORE:        c: 70 47         bx lr
+
+# AFTER: Disassembly of section .text:
+# AFTER:     1000: 70 47         bx lr
+# AFTER:     1002: 00 bf         nop
+# AFTER:     1004: 41 f2 01 00   movw r0, #4097
+# AFTER:     1008: c0 f2 40 00   movt r0, #64
+# AFTER:     100c: 70 47         bx lr
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     704700BF40F20000C0F200007047
+    Relocations:
+      - VirtualAddress:  4
+        SymbolName:      function
+        Type:            17
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            function
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            get_function
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/armnt-movt32t.test b/test/COFF/armnt-movt32t.test
new file mode 100644 (file)
index 0000000..6a9bf25
--- /dev/null
@@ -0,0 +1,72 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld-link /entry:get_buffer /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+# BEFORE: Disassembly of section .text:
+# BEFORE:        0: 40 f2 00 00   movw r0, #0
+# BEFORE:        4: c0 f2 00 00   movt r0, #0
+# BEFORE:        8: 70 47         bx lr
+
+# AFTER: Disassembly of section .text:
+# AFTER:        0: 41 f2 00 00   movw r0, #4096
+# AFTER:        4: c0 f2 40 00   movt r0, #64
+# AFTER:        8: 70 47         bx lr
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     40F20000C0F200007047
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      buffer
+        Type:            17
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     '62756666657200'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          10
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          7
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            get_buffer
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            buffer
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/associative-comdat.s b/test/COFF/associative-comdat.s
new file mode 100644 (file)
index 0000000..dd54195
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t1.obj
+# RUN: llvm-mc -triple=x86_64-windows-msvc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj
+
+# RUN: lld-link -entry:main %t1.obj %t2.obj -out:%t.gc.exe
+# RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s
+
+# RUN: lld-link -entry:main %t1.obj %t2.obj -opt:noref -out:%t.nogc.exe
+# RUN: llvm-readobj -sections %t.nogc.exe | FileCheck %s
+
+# CHECK: Sections [
+# CHECK:   Section {
+# CHECK:     Number: 1
+# CHECK-LABEL:     Name: .data (2E 64 61 74 61 00 00 00)
+# CHECK-NEXT:     VirtualSize: 0x4
+# CHECK:   Section {
+# CHECK-LABEL:     Name: .rdata (2E 72 64 61 74 61 00 00)
+#             This is the critical check to show that only *one* definition of
+#             foo_assoc was retained. This *must* be 8, not 16.
+# CHECK-NEXT:     VirtualSize: 0x8
+
+        .text
+        .def     main;
+        .scl    2;
+        .type   32;
+        .endef
+        .globl  main                    # -- Begin function main
+        .p2align        4, 0x90
+main:                                   # @main
+# BB#0:
+        movl    foo(%rip), %eax
+        retq
+                                        # -- End function
+
+# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat
+# associative with it. foo_assoc should be discarded iff foo is discarded,
+# either by linker GC or normal comdat merging.
+
+        .section        .rdata,"dr",associative,foo
+        .p2align        3
+        .quad   foo
+
+        .section        .data,"dw",discard,foo
+        .globl  foo                     # @foo
+        .p2align        2
+foo:
+        .long   42
diff --git a/test/COFF/base.test b/test/COFF/base.test
new file mode 100644 (file)
index 0000000..662632b
--- /dev/null
@@ -0,0 +1,57 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT-HEADER %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DEFAULT-TEXT %s
+
+# DEFAULT-HEADER:    ImageBase: 0x140000000
+# DEFAULT-TEXT:      Contents of section .text:
+# DEFAULT-TEXT-NEXT: 1000 00000040 01000000
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /base:0x280000000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BASE-HEADER %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=BASE-TEXT %s
+
+# BASE-HEADER: ImageBase: 0x280000000
+# BASE-TEXT:      Contents of section .text:
+# BASE-TEXT-NEXT: 1000 00000080 02000000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/baserel.test b/test/COFF/baserel.test
new file mode 100644 (file)
index 0000000..ce0b276
--- /dev/null
@@ -0,0 +1,215 @@
+# RUN: yaml2obj < %s > %t.obj
+#
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=BASEREL
+#
+# RUN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=NOBASEREL
+#
+# BASEREL:      BaseReloc [
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x2007
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x200C
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x201E
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: ABSOLUTE
+# BASEREL-NEXT:   Address: 0x2000
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x3007
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x300C
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: DIR64
+# BASEREL-NEXT:   Address: 0x301E
+# BASEREL-NEXT: }
+# BASEREL-NEXT: Entry {
+# BASEREL-NEXT:   Type: ABSOLUTE
+# BASEREL-NEXT:   Address: 0x3000
+# BASEREL-NEXT: }
+#
+# NOBASEREL:      BaseReloc [
+# NOBASEREL-NEXT: ]
+#
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck %s \
+# RUN:   --check-prefix=BASEREL-HEADER
+#
+# RN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
+# RN: llvm-readobj -file-headers %t.exe | FileCheck %s \
+# RN:   --check-prefix=NOBASEREL-HEADER
+#
+# BASEREL-HEADER-NOT: IMAGE_FILE_RELOCS_STRIPPED
+#
+# NOBASEREL-HEADER: IMAGE_FILE_RELOCS_STRIPPED
+#
+# BASEREL-HEADER:      BaseRelocationTableRVA: 0x5000
+# BASEREL-HEADER:      BaseRelocationTableSize: 0x20
+# BASEREL-HEADER:      Name: .reloc (2E 72 65 6C 6F 63 00 00)
+# BASEREL-HEADER-NEXT: VirtualSize: 0x20
+# BASEREL-HEADER-NEXT: VirtualAddress: 0x5000
+# BASEREL-HEADER-NEXT: RawDataSize: 512
+# BASEREL-HEADER-NEXT: PointerToRawData: 0xC00
+# BASEREL-HEADER-NEXT: PointerToRelocations: 0x0
+# BASEREL-HEADER-NEXT: PointerToLineNumbers: 0x0
+# BASEREL-HEADER-NEXT: RelocationCount: 0
+# BASEREL-HEADER-NEXT: LineNumberCount: 0
+# BASEREL-HEADER-NEXT: Characteristics [ (0x42000040)
+# BASEREL-HEADER-NEXT:   IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+# BASEREL-HEADER-NEXT:   IMAGE_SCN_MEM_DISCARDABLE (0x2000000)
+# BASEREL-HEADER-NEXT:   IMAGE_SCN_MEM_READ (0x40000000)
+# BASEREL-HEADER-NEXT: ]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .text2
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     48656C6C6F0048656C6C6F20576F726C6400
+symbols:
+  - Name:            "@comp.id"
+    Value:           10394907
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .text2
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          18
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            MessageBoxA
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            ExitProcess
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            message
+    Value:           6
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            caption
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            abs_symbol
+    Value:           0xDEADBEEF
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/cl-gl.test b/test/COFF/cl-gl.test
new file mode 100644 (file)
index 0000000..3061150
--- /dev/null
@@ -0,0 +1,4 @@
+# RUN: not lld-link /out:%t.exe /entry:main %S/Inputs/cl-gl.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: is not a native COFF file. Recompile without /GL
diff --git a/test/COFF/combined-resources.test b/test/COFF/combined-resources.test
new file mode 100644 (file)
index 0000000..e8d5d65
--- /dev/null
@@ -0,0 +1,213 @@
+// Check that lld properly handles merging multiple .res files.
+// The inputs were generated with the following commands, using the original
+// Windows rc.exe
+// > rc /fo combined-resources.res /nologo combined-resources.rc
+// > rc /fo combined-resources-2.res /nologo combined-resources-2.rc
+
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res \
+# RUN:   %p/Inputs/combined-resources.res %p/Inputs/combined-resources-2.res
+
+# RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \
+# RUN:   FileCheck %s
+
+CHECK:      ResourceTableRVA: 0x1000
+CHECK-NEXT: ResourceTableSize: 0xC1C
+CHECK-DAG:  Resources [
+CHECK-NEXT:   Total Number of Resources: 13
+CHECK-DAG:  .rsrc Data (
+CHECK-NEXT: 0000: 00000000 00000000 00000000 01000600  |................|
+CHECK-NEXT: 0010: 38030080 48000080 02000000 60000080  |8...H.......`...|
+CHECK-NEXT: 0020: 04000000 80000080 05000000 A0000080  |................|
+CHECK-NEXT: 0030: 06000000 B8000080 09000000 D0000080  |................|
+CHECK-NEXT: 0040: 0A000000 F0000080 00000000 00000000  |................|
+CHECK-NEXT: 0050: 00000000 01000000 50030080 08010080  |........P.......|
+CHECK-NEXT: 0060: 00000000 00000000 00000000 02000000  |................|
+CHECK-NEXT: 0070: FE020080 20010080 0C030080 38010080  |.... .......8...|
+CHECK-NEXT: 0080: 00000000 00000000 00000000 01000100  |................|
+CHECK-NEXT: 0090: 2C030080 50010080 60380000 68010080  |,...P...`8..h...|
+CHECK-NEXT: 00A0: 00000000 00000000 00000000 01000000  |................|
+CHECK-NEXT: 00B0: 16030080 80010080 00000000 00000000  |................|
+CHECK-NEXT: 00C0: 00000000 00000100 01000000 98010080  |................|
+CHECK-NEXT: 00D0: 00000000 00000000 00000000 01000100  |................|
+CHECK-NEXT: 00E0: E0020080 B0010080 0C000000 D0010080  |................|
+CHECK-NEXT: 00F0: 00000000 00000000 00000000 01000000  |................|
+CHECK-NEXT: 0100: 66030080 E8010080 00000000 00000000  |f...............|
+CHECK-NEXT: 0110: 00000000 00000100 09040000 10020000  |................|
+CHECK-NEXT: 0120: 00000000 00000000 00000000 00000100  |................|
+CHECK-NEXT: 0130: 09040000 20020000 00000000 00000000  |.... ...........|
+CHECK-NEXT: 0140: 00000000 00000100 09040000 30020000  |............0...|
+CHECK-NEXT: 0150: 00000000 00000000 00000000 00000100  |................|
+CHECK-NEXT: 0160: 090C0000 40020000 00000000 00000000  |....@...........|
+CHECK-NEXT: 0170: 00000000 00000100 04080000 50020000  |............P...|
+CHECK-NEXT: 0180: 00000000 00000000 00000000 00000100  |................|
+CHECK-NEXT: 0190: 09040000 60020000 00000000 00000000  |....`...........|
+CHECK-NEXT: 01A0: 00000000 00000100 09040000 70020000  |............p...|
+CHECK-NEXT: 01B0: 00000000 00000000 00000000 00000200  |................|
+CHECK-NEXT: 01C0: 09040000 80020000 04080000 90020000  |................|
+CHECK-NEXT: 01D0: 00000000 00000000 00000000 00000100  |................|
+CHECK-NEXT: 01E0: 09040000 A0020000 00000000 00000000  |................|
+CHECK-NEXT: 01F0: 00000000 00000300 09040000 B0020000  |................|
+CHECK-NEXT: 0200: 04080000 C0020000 07100000 D0020000  |................|
+CHECK-NEXT: 0210: FC1A0000 39000000 00000000 00000000  |....9...........|
+CHECK-NEXT: 0220: C4130000 28030000 00000000 00000000  |....(...........|
+CHECK-NEXT: 0230: EC160000 28030000 00000000 00000000  |....(...........|
+CHECK-NEXT: 0240: CC1A0000 30000000 00000000 00000000  |....0...........|
+CHECK-NEXT: 0250: 141A0000 2E000000 00000000 00000000  |................|
+CHECK-NEXT: 0260: 441A0000 6C000000 00000000 00000000  |D...l...........|
+CHECK-NEXT: 0270: 7C130000 2A000000 00000000 00000000  ||...*...........|
+CHECK-NEXT: 0280: AC130000 18000000 00000000 00000000  |................|
+CHECK-NEXT: 0290: 041C0000 18000000 00000000 00000000  |................|
+CHECK-NEXT: 02A0: B41A0000 18000000 00000000 00000000  |................|
+CHECK-NEXT: 02B0: 3C1B0000 36000000 00000000 00000000  |<...6...........|
+CHECK-NEXT: 02C0: 741B0000 43000000 00000000 00000000  |t...C...........|
+CHECK-NEXT: 02D0: BC1B0000 42000000 00000000 00000000  |....B...........|
+CHECK-NEXT: 02E0: 0E004D00 59004100 43004300 45004C00  |..M.Y.A.C.C.E.L.|
+CHECK-NEXT: 02F0: 45005200 41005400 4F005200 53000600  |E.R.A.T.O.R.S...|
+CHECK-NEXT: 0300: 43005500 52005300 4F005200 04004F00  |C.U.R.S.O.R...O.|
+CHECK-NEXT: 0310: 4B004100 59000A00 54004500 53005400  |K.A.Y...T.E.S.T.|
+CHECK-NEXT: 0320: 44004900 41004C00 4F004700 05002200  |D.I.A.L.O.G...".|
+CHECK-NEXT: 0330: 45004100 54002200 0B005300 54005200  |E.A.T."...S.T.R.|
+CHECK-NEXT: 0340: 49004E00 47004100 52005200 41005900  |I.N.G.A.R.R.A.Y.|
+CHECK-NEXT: 0350: 0A004D00 59005200 45005300 4F005500  |..M.Y.R.E.S.O.U.|
+CHECK-NEXT: 0360: 52004300 45000900 52004100 4E004400  |R.C.E...R.A.N.D.|
+CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000500  |O.M.D.A.T.......|
+CHECK-NEXT: 0380: 48006500 6C006C00 6F000000 00000000  |H.e.l.l.o.......|
+CHECK-NEXT: 0390: 00000000 00000000 00000000 00000000  |................|
+CHECK-NEXT: 03A0: 00000000 00000000 00000000 11000300  |................|
+CHECK-NEXT: 03B0: E7030000 0D004400 4C040000 82001200  |......D.L.......|
+CHECK-NEXT: 03C0: BC010000 28000000 10000000 10000000  |....(...........|
+CHECK-NEXT: 03D0: 01001800 00000000 00030000 C40E0000  |................|
+CHECK-NEXT: 03E0: C40E0000 00000000 00000000 FFFFFFFF  |................|
+CHECK-NEXT: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0420: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0430: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0440: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0460: FF7F7F7F 7C7C7C78 78787575 75FFFFFF  |....|||xxxuuu...|
+CHECK-NEXT: 0470: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF 979797FF FFFFFFFF  |................|
+CHECK-NEXT: 0490: FF838383 AAAAAADB DBDB7979 79757575  |..........yyyuuu|
+CHECK-NEXT: 04A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF 9C9C9C98 9898FFFF  |................|
+CHECK-NEXT: 04C0: FF888888 DBDBDBB7 B7B77D7D 7DFFFFFF  |..........}}}...|
+CHECK-NEXT: 04D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF A0A0A09C 9C9C9393  |................|
+CHECK-NEXT: 04F0: 93ADADAD F2F2F284 84848181 81FFFFFF  |................|
+CHECK-NEXT: 0500: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF A4A4A4D7 D7D79D9D  |................|
+CHECK-NEXT: 0520: 9DD0D0D0 EEEEEE91 91918D8D 8DFFFFFF  |................|
+CHECK-NEXT: 0530: FFFFFF81 81817E7E 7EFFFFFF FFFFFFFF  |......~~~.......|
+CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF A9A9A9F2 F2F2E5E5  |................|
+CHECK-NEXT: 0550: E5E2E2E2 95959591 91918D8D 8D898989  |................|
+CHECK-NEXT: 0560: 868686FF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF ADADADF2 F2F2E1E1  |................|
+CHECK-NEXT: 0580: E1DFDFDF E7E7E7E4 E4E4BBBB BB8E8E8E  |................|
+CHECK-NEXT: 0590: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF B5B5B5F2 F2F2E8E8  |................|
+CHECK-NEXT: 05B0: E8E7E7E7 EAEAEAC6 C6C69E9E 9EFFFFFF  |................|
+CHECK-NEXT: 05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF B9B9B9F4 F4F4ECEC  |................|
+CHECK-NEXT: 05E0: ECEDEDED CBCBCBA7 A7A7FFFF FFFFFFFF  |................|
+CHECK-NEXT: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF BDBDBDF7 F7F7EFEF  |................|
+CHECK-NEXT: 0610: EFD0D0D0 AFAFAFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF C1C1C1F7 F7F7D5D5  |................|
+CHECK-NEXT: 0640: D5B6B6B6 FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF C4C4C4D9 D9D9BEBE  |................|
+CHECK-NEXT: 0670: BEFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0680: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF C8C8C8C5 C5C5FFFF  |................|
+CHECK-NEXT: 06A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 06B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF CBCBCBFF FFFFFFFF  |................|
+CHECK-NEXT: 06D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF 28000000  |............(...|
+CHECK-NEXT: 06F0: 10000000 10000000 01001800 00000000  |................|
+CHECK-NEXT: 0700: 00030000 C40E0000 C40E0000 00000000  |................|
+CHECK-NEXT: 0710: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0720: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0730: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0740: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0750: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0760: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0770: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0780: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0790: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 07A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 07B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 07C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 07D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 07E0: A0E3A901 B31801B3 1801B318 01B31801  |................|
+CHECK-NEXT: 07F0: B31801B3 1861D06F FFFFFFFF FFFFFFFF  |.....a.o........|
+CHECK-NEXT: 0800: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0810: 01B31800 D7331CDB 49DBF9E2 9BEFAF00  |.....3..I.......|
+CHECK-NEXT: 0820: D73300D7 3301B318 FFFFFFFF FFFFFFFF  |.3..3...........|
+CHECK-NEXT: 0830: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0840: 01B31800 DE55F6FE F9DBFAE7 FEFFFE86  |.....U..........|
+CHECK-NEXT: 0850: EFAE00DE 5501B318 FFFFFFFF FFFFFFFF  |....U...........|
+CHECK-NEXT: 0860: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0870: 01B31800 E676DBFB EC00E676 57EFA5FB  |.....v.....vW...|
+CHECK-NEXT: 0880: FFFD55EE A401B318 FFFFFFFF FFFFFFFF  |..U.............|
+CHECK-NEXT: 0890: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 08A0: 01B31800 ED9800ED 9800ED98 00ED9887  |................|
+CHECK-NEXT: 08B0: F7CFFEFF FF01B318 FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 08C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 08D0: 01B31800 F4BA00F4 BA00F4BA 00F4BA00  |................|
+CHECK-NEXT: 08E0: F4BA9CFB E401B318 FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 08F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0900: 01B31800 FBDB00FB DB00FBDB 00FBDB00  |................|
+CHECK-NEXT: 0910: FBDB00FB DB01B318 FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0920: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0930: 9FE2A801 B31801B3 1801B318 01B31801  |................|
+CHECK-NEXT: 0940: B31801B3 1861D06F FFFFFFFF FFFFFFFF  |.....a.o........|
+CHECK-NEXT: 0950: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0960: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0970: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0980: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0990: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 09A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 09B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 09C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 09D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 09E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 09F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0A00: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................|
+CHECK-NEXT: 0A10: FFFFFFFF 00000000 00006400 79007500  |..........d.y.u.|
+CHECK-NEXT: 0A20: 00000000 65007300 68006100 6C006100  |....e.s.h.a.l.a.|
+CHECK-NEXT: 0A30: 00008000 66006B00 61006F00 79006100  |....f.k.a.o.y.a.|
+CHECK-NEXT: 0A40: 00000000 0000C080 00000000 02000A00  |................|
+CHECK-NEXT: 0A50: 0A00C800 2C010000 00005400 65007300  |....,.....T.e.s.|
+CHECK-NEXT: 0A60: 74000000 01000250 00000000 0A000A00  |t......P........|
+CHECK-NEXT: 0A70: E6000E00 0100FFFF 82004300 6F006E00  |..........C.o.n.|
+CHECK-NEXT: 0A80: 74006900 6E007500 65003A00 00000000  |t.i.n.u.e.:.....|
+CHECK-NEXT: 0A90: 00000150 00000000 42008600 A1000D00  |...P....B.......|
+CHECK-NEXT: 0AA0: 0200FFFF 80002600 4F004B00 00000000  |......&.O.K.....|
+CHECK-NEXT: 0AB0: 00000000 11005800 A4000000 0D004800  |......X.......H.|
+CHECK-NEXT: 0AC0: 2E160000 82001200 BC010000 00000000  |................|
+CHECK-NEXT: 0AD0: 00006400 66006900 73006800 00000000  |..d.f.i.s.h.....|
+CHECK-NEXT: 0AE0: 65007300 61006C00 61006400 00008000  |e.s.a.l.a.d.....|
+CHECK-NEXT: 0AF0: 66006400 75006300 6B000000 74686973  |f.d.u.c.k...this|
+CHECK-NEXT: 0B00: 20697320 61207573 65722064 6566696E  | is a user defin|
+CHECK-NEXT: 0B10: 65642072 65736F75 72636500 69742063  |ed resource.it c|
+CHECK-NEXT: 0B20: 6F6E7461 696E7320 6D616E79 20737472  |ontains many str|
+CHECK-NEXT: 0B30: 696E6773 00000000 00000000 74686973  |ings........this|
+CHECK-NEXT: 0B40: 20697320 61207261 6E646F6D 20626974  | is a random bit|
+CHECK-NEXT: 0B50: 206F6620 64617461 20746861 74206D65  | of data that me|
+CHECK-NEXT: 0B60: 616E7320 6E6F7468 696E6700 A9230E14  |ans nothing..#..|
+CHECK-NEXT: 0B70: F4F60000 7A686534 20736869 34207969  |....zhe4 shi4 yi|
+CHECK-NEXT: 0B80: 31676534 20737569 326A6931 20646520  |1ge4 sui2ji1 de |
+CHECK-NEXT: 0B90: 73687534 6A75342C 207A6865 34207969  |shu4ju4, zhe4 yi|
+CHECK-NEXT: 0BA0: 34776569 347A6865 20736865 6E326D65  |4wei4zhe shen2me|
+CHECK-NEXT: 0BB0: 00A9230E 14F4F600 00000000 44696573  |..#.........Dies|
+CHECK-NEXT: 0BC0: 20697374 2065696E 207A7566 C3A46C6C  | ist ein zuf..ll|
+CHECK-NEXT: 0BD0: 69676573 20426974 20766F6E 20446174  |iges Bit von Dat|
+CHECK-NEXT: 0BE0: 656E2C20 64696520 6E696368 74732062  |en, die nichts b|
+CHECK-NEXT: 0BF0: 65646575 74657400 A9230E14 F4F60000  |edeutet..#......|
+CHECK-NEXT: 0C00: 00000000 11000300 E7030000 0D004400  |..............D.|
+CHECK-NEXT: 0C10: 4C040000 82001200 BC010000           |L...........|
+CHECK-NEXT: )
diff --git a/test/COFF/common.test b/test/COFF/common.test
new file mode 100644 (file)
index 0000000..4a00153
--- /dev/null
@@ -0,0 +1,103 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# Operands of B8 (MOV EAX) are common symbols
+# CHECK: 3000: b8 00 10 00 40
+# CHECK: 3005: b8 04 10 00 40
+# CHECK: 300a: b8 20 10 00 40
+# CHECK: 300f: b8 60 10 00 40
+# CHECK: 3014: b8 70 10 00 40
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     b800000000b800000000b800000000b800000000b800000000
+    Relocations:
+      - VirtualAddress:  1
+        SymbolName:      bssdata4
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  6
+        SymbolName:      bsspad1
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  11
+        SymbolName:      bssdata64
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  16
+        SymbolName:      bsspad2
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  21
+        SymbolName:      bssdata16
+        Type:            IMAGE_REL_AMD64_ADDR32
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     03000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 5
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bssdata4
+    Value:           4
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bsspad1
+    Value:           1
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bssdata64
+    Value:           64
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bsspad2
+    Value:           1
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bssdata16
+    Value:           16
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/conflict-mangled.test b/test/COFF/conflict-mangled.test
new file mode 100644 (file)
index 0000000..2f028ef
--- /dev/null
@@ -0,0 +1,37 @@
+# REQUIRES: system-windows
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %s > %t2.obj
+# RUN: not lld-link /out:%t.exe %t1.obj %t2.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: duplicate symbol: "int __cdecl mangled(void)" (?mangled@@YAHXZ) in {{.+}}1.obj and in {{.+}}2.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '?mangled@@YAHXZ'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/conflict.test b/test/COFF/conflict.test
new file mode 100644 (file)
index 0000000..ae8e6c8
--- /dev/null
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %s > %t2.obj
+# RUN: not lld-link /out:%t.exe %t1.obj %t2.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# RUN: llvm-as -o %t.lto1.obj %S/Inputs/conflict.ll
+# RUN: llvm-as -o %t.lto2.obj %S/Inputs/conflict.ll
+# RUN: not lld-link /out:%t.exe %t.lto1.obj %t.lto2.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: duplicate symbol: foo in {{.+}}1.obj and in {{.+}}2.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/constant-export.test b/test/COFF/constant-export.test
new file mode 100644 (file)
index 0000000..8059766
--- /dev/null
@@ -0,0 +1,92 @@
+# RUN: mkdir -p %t
+# RUN: yaml2obj -o %t/constant-export.obj %s
+# RUN: lld-link /machine:x86 /dll /entry:__CFConstantStringClassReference -out:%t/constant-export.dll %t/constant-export.obj
+# RUN: llvm-readobj -coff-exports %t/constant-export.lib | FileCheck %s
+
+# CHECK: Type: const
+# CHECK: Name type: noprefix
+# CHECK: Symbol: __imp____CFConstantStringClassReference
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     20202D6578706F72743A5F5F5F4346436F6E7374616E74537472696E67436C6173735265666572656E63652C434F4E5354414E54
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          52
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1983959296
+      Number:          4
+  - Name:            '@feat.00'
+    Value:           1
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            ___CFConstantStringClassReference
+    Value:           128
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/constant.test b/test/COFF/constant.test
new file mode 100644 (file)
index 0000000..02d6b3e
--- /dev/null
@@ -0,0 +1,6 @@
+REQUIRES: x86
+RUN: mkdir -p %t
+RUN: llvm-mc -triple i686-unknown-windows-msvc -filetype obj -o %t/import.o %S/Inputs/constant-import.s
+RUN: llc -mtriple i686-unknown-windows-msvc -filetype obj -o %t/export.o %S/Inputs/constant-export.ll
+RUN: lld-link -machine:x86 -dll -out:%t/export.dll %t/export.o -entry:__CFConstantStringClassReference
+RUN: lld-link -machine:x86 -dll -out:%t/import.dll %t/import.o %t/export.lib
diff --git a/test/COFF/debug.test b/test/COFF/debug.test
new file mode 100644 (file)
index 0000000..3921e0c
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console %t.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            debug
+    Value:           0
+    SectionNumber:   -2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/def-export-stdcall.s b/test/COFF/def-export-stdcall.s
new file mode 100644 (file)
index 0000000..d7700d9
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj
+# RUN: echo -e "LIBRARY foo\nEXPORTS\n  stdcall" > %t.def
+# RUN: lld-link -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib
+# RUN: llvm-nm %t.lib | FileCheck %s
+# CHECK: __imp__stdcall@8
+# CHECK: _stdcall@8
+
+        .def     _stdcall@8;
+        .scl    2;
+        .type   32;
+        .endef
+        .globl  _stdcall@8
+_stdcall@8:
+        movl    8(%esp), %eax
+        addl    4(%esp), %eax
+        retl    $8
+
+        .def     _dllmain;
+        .scl    2;
+        .type   32;
+        .endef
+        .globl  _dllmain
+_dllmain:
+        retl
+
diff --git a/test/COFF/def-name.test b/test/COFF/def-name.test
new file mode 100644 (file)
index 0000000..b971007
--- /dev/null
@@ -0,0 +1,26 @@
+# RUN: rm -rf %t
+# RUN: mkdir -p %t
+# RUN: cd %t
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > in.obj
+
+# RUN: lld-link /entry:main in.obj
+# RUN: lld-link /entry:main /dll in.obj
+
+# RUN: echo -e "NAME foo\n" > fooexe.def
+# RUN: echo -e "LIBRARY foo\n" > foodll.def
+# RUN: lld-link /entry:main /def:fooexe.def in.obj
+# RUN: lld-link /entry:main /def:foodll.def /dll in.obj
+
+# RUN: lld-link /entry:main /out:bar.exe /def:fooexe.def in.obj
+# RUN: lld-link /entry:main /out:bar.dll /def:foodll.def /dll in.obj
+
+# RUN: llvm-readobj in.exe | FileCheck %s
+# RUN: llvm-readobj in.dll | FileCheck %s
+
+# RUN: llvm-readobj foo.exe | FileCheck %s
+# RUN: llvm-readobj foo.dll | FileCheck %s
+
+# RUN: llvm-readobj bar.exe | FileCheck %s
+# RUN: llvm-readobj bar.dll | FileCheck %s
+
+CHECK: File:
diff --git a/test/COFF/defparser.test b/test/COFF/defparser.test
new file mode 100644 (file)
index 0000000..2e5223a
--- /dev/null
@@ -0,0 +1,13 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: echo -e "LIBRARY foo\nEXPORTS ? @" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
+
+# RUN: echo -e "LIBRARY foo\nHEAP abc" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
+
+# RUN: echo -e "LIBRARY foo\nSTACK abc" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
+
+# RUN: echo -e "foo" > %t.def
+# RUN: not lld-link /def:%t.def %t.obj
diff --git a/test/COFF/delayimports-error.test b/test/COFF/delayimports-error.test
new file mode 100644 (file)
index 0000000..3fea1bc
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: mkdir -p %t.dir
+# RUN: yaml2obj < %p/Inputs/delayimports-error.yaml > %t1.obj
+# RUN: lld-link /out:%t.dir/foo.dll /dll %t1.obj /export:datasym,DATA /noentry
+
+# RUN: yaml2obj < %s > %t2.obj
+# RUN: not lld-link /out:%t.exe /entry:main %t2.obj %t.dir/foo.lib /delayload:foo.dll \
+# RUN:   /alternatename:__delayLoadHelper2=main /opt:noref >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: cannot delay-load foo.dll due to import of data: __imp_datasym
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp_datasym
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/delayimports.test b/test/COFF/delayimports.test
new file mode 100644 (file)
index 0000000..2c27d58
--- /dev/null
@@ -0,0 +1,41 @@
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   %p/Inputs/hello64.obj %p/Inputs/std64.lib /delayload:STD64.DLL \
+# RUN:   /alternatename:__delayLoadHelper2=main
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+
+IMPORT:      DelayImport {
+IMPORT-NEXT:   Name: std64.dll
+IMPORT-NEXT:   Attributes: 0x1
+IMPORT-NEXT:   ModuleHandle: 0x1018
+IMPORT-NEXT:   ImportAddressTable: 0x1020
+IMPORT-NEXT:   ImportNameTable: 0x3040
+IMPORT-NEXT:   BoundDelayImportTable: 0x0
+IMPORT-NEXT:   UnloadDelayImportTable: 0x0
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: ExitProcess (0)
+IMPORT-NEXT:     Address: 0x140002066
+IMPORT-NEXT:   }
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol:  (50)
+IMPORT-NEXT:     Address: 0x1400020BD
+IMPORT-NEXT:   }
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: MessageBoxA (0)
+IMPORT-NEXT:     Address: 0x140002114
+IMPORT-NEXT:   }
+IMPORT-NEXT: }
+
+BASEREL:      BaseReloc [
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: DIR64
+BASEREL-NEXT:     Address: 0x1020
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: DIR64
+BASEREL-NEXT:     Address: 0x1028
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: DIR64
+BASEREL-NEXT:     Address: 0x1030
+BASEREL-NEXT:   }
diff --git a/test/COFF/delayimports32.test b/test/COFF/delayimports32.test
new file mode 100644 (file)
index 0000000..53aadbb
--- /dev/null
@@ -0,0 +1,87 @@
+# REQUIRES: x86
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /alternatename:___delayLoadHelper2@8=_main@0 \
+# RUN:   /debug /delayload:std32.dll /out:%t.exe
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s
+
+IMPORT:      Format: COFF-i386
+IMPORT-NEXT: Arch: i386
+IMPORT-NEXT: AddressSize: 32bit
+IMPORT-NEXT: DelayImport {
+IMPORT-NEXT:   Name: std32.dll
+IMPORT-NEXT:   Attributes: 0x1
+IMPORT-NEXT:   ModuleHandle: 0x1018
+IMPORT-NEXT:   ImportAddressTable: 0x1020
+IMPORT-NEXT:   ImportNameTable: 0x4040
+IMPORT-NEXT:   BoundDelayImportTable: 0x0
+IMPORT-NEXT:   UnloadDelayImportTable: 0x0
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: ExitProcess (0)
+IMPORT-NEXT:     Address: 0x402029
+IMPORT-NEXT:   }
+IMPORT-NEXT:   Import {
+IMPORT-NEXT:     Symbol: MessageBoxA (0)
+IMPORT-NEXT:     Address: 0x40203E
+IMPORT-NEXT:   }
+IMPORT-NEXT: }
+
+BASEREL:      BaseReloc [
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x1020
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x1024
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2005
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x200C
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x201F
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2025
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x202C
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2031
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2041
+BASEREL-NEXT:   }
+BASEREL-NEXT:   Entry {
+BASEREL-NEXT:     Type: HIGHLOW
+BASEREL-NEXT:     Address: 0x2046
+BASEREL-NEXT:   }
+BASEREL-NEXT: ]
+
+DISASM:      202b:      68 20 10 40 00  pushl   $4198432
+DISASM-NEXT: 2030:      68 00 40 40 00  pushl   $4210688
+DISASM-NEXT: 2035:      e8 c6 ff ff ff  calll   -58 <_main@0>
+DISASM-NEXT: 203a:      5a      popl    %edx
+DISASM-NEXT: 203b:      59      popl    %ecx
+DISASM-NEXT: 203c:      ff e0   jmpl    *%eax
+DISASM-NEXT: 203e:      51      pushl   %ecx
+DISASM-NEXT: 203f:      52      pushl   %edx
+DISASM-NEXT: 2040:      68 24 10 40 00  pushl   $4198436
+DISASM-NEXT: 2045:      68 00 40 40 00  pushl   $4210688
+DISASM-NEXT: 204a:      e8 b1 ff ff ff  calll   -79 <_main@0>
+DISASM-NEXT: 204f:      5a      popl    %edx
+DISASM-NEXT: 2050:      59      popl    %ecx
+DISASM-NEXT: 2051:      ff e0   jmpl    *%eax
diff --git a/test/COFF/dll.test b/test/COFF/dll.test
new file mode 100644 (file)
index 0000000..abd39f4
--- /dev/null
@@ -0,0 +1,50 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
+# RUN:   /export:mangled
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=EXPORT %s
+
+EXPORT:      Export Table:
+EXPORT:      DLL name: dll.test.tmp.dll
+EXPORT:      Ordinal      RVA  Name
+EXPORT-NEXT:       0        0
+EXPORT-NEXT:       1   0x1008  exportfn1
+EXPORT-NEXT:       2   0x1010  exportfn2
+EXPORT-NEXT:       3   0x1010  exportfn3
+EXPORT-NEXT:       4   0x1010  mangled
+
+# RUN: yaml2obj < %p/Inputs/export2.yaml > %t5.obj
+# RUN: rm -f %t5.lib
+# RUN: llvm-ar cru %t5.lib %t5.obj
+# RUN: lld-link /out:%t5.dll /dll %t.obj %t5.lib /export:mangled2
+# RUN: llvm-objdump -p %t5.dll | FileCheck -check-prefix=EXPORT2 %s
+
+EXPORT2:      Export Table:
+EXPORT2:      DLL name: dll.test.tmp5.dll
+EXPORT2:      Ordinal      RVA  Name
+EXPORT2-NEXT:       0        0
+EXPORT2-NEXT:       1   0x1010  exportfn3
+EXPORT2-NEXT:       2   0x101c  mangled2
+
+# RUN: llvm-as -o %t.lto.obj %p/Inputs/export.ll
+# RUN: lld-link /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.lto.dll | FileCheck -check-prefix=EXPORT-LTO %s
+
+EXPORT-LTO:      Export Table:
+EXPORT-LTO:      DLL name: dll.test.tmp.lto.dll
+EXPORT-LTO:      Ordinal      RVA  Name
+EXPORT-LTO-NEXT:       0        0
+EXPORT-LTO-NEXT:       1   0x1010  exportfn1
+EXPORT-LTO-NEXT:       2   0x1020  exportfn2
+EXPORT-LTO-NEXT:       3   0x1030  exportfn3
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /implib:%t2.lib \
+# RUN:   /export:exportfn1 /export:exportfn2
+# RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj
+# RUN: lld-link /out:%t2.exe /entry:main %t2.obj %t2.lib
+# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s
+
+# RUN: lld-link /out:%t2.lto.exe /entry:main %t2.obj %t.lto.lib
+# RUN: llvm-readobj -coff-imports %t2.lto.exe | FileCheck -check-prefix=IMPORT %s
+
+IMPORT: Symbol: exportfn1
+IMPORT: Symbol: exportfn2
diff --git a/test/COFF/dllimport-gc.test b/test/COFF/dllimport-gc.test
new file mode 100644 (file)
index 0000000..d8523fb
--- /dev/null
@@ -0,0 +1,56 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj
+# RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1
+
+# RUN: yaml2obj < %p/Inputs/oldname.yaml > %t-oldname.obj
+
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link /out:%t1.exe /entry:main %t.obj %t-oldname.obj %t.lib
+# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=REF %s
+# REF-NOT: Symbol: exportfn1
+
+# RUN: lld-link /out:%t2.exe /entry:main %t.obj %t-oldname.obj %t.lib /opt:noref
+# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=NOREF %s
+# NOREF: Symbol: exportfn1
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            exportfn1_alias
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/driver-windows.test b/test/COFF/driver-windows.test
new file mode 100644 (file)
index 0000000..1b93a53
--- /dev/null
@@ -0,0 +1,3 @@
+# REQUIRES: system-windows
+# RUN: not LLD-LINK 2>&1 | FileCheck %s
+CHECK: no input files
diff --git a/test/COFF/driver.test b/test/COFF/driver.test
new file mode 100644 (file)
index 0000000..0832350
--- /dev/null
@@ -0,0 +1,3 @@
+# RUN: not lld-link nosuchfile.obj >& %t.log
+# RUN: FileCheck -check-prefix=MISSING %s < %t.log
+MISSING: nosuchfile.obj: {{[Nn]}}o such file or directory
diff --git a/test/COFF/entry-inference.test b/test/COFF/entry-inference.test
new file mode 100644 (file)
index 0000000..2eb9a68
--- /dev/null
@@ -0,0 +1,50 @@
+# RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=MAIN %s < %t.log
+
+# RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
+
+# RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
+
+# RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
+
+# MAIN:     <root>: undefined symbol: mainCRTStartup
+# WMAIN:    <root>: undefined symbol: wmainCRTStartup
+# WINMAIN:  <root>: undefined symbol: WinMainCRTStartup
+# WWINMAIN: <root>: undefined symbol: wWinMainCRTStartup
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            ENTRYNAME
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entry-inference2.test b/test/COFF/entry-inference2.test
new file mode 100644 (file)
index 0000000..a66422f
--- /dev/null
@@ -0,0 +1,39 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj /verbose > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Entry name inferred: WinMainCRTStartup
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f616c7465726e6174656e616d653a6d61696e3d57696e4d61696e00  # /alternatename:main=WinMain
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            WinMain
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entry-inference32.test b/test/COFF/entry-inference32.test
new file mode 100644 (file)
index 0000000..231b468
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj /verbose > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Entry name inferred: _WinMainCRTStartup
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _WinMain@16
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entry-mangled.test b/test/COFF/entry-mangled.test
new file mode 100644 (file)
index 0000000..1140e82
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/entry-mangled.ll
+# RUN: lld-link /out:%t.exe /entry:main %t.lto.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '?main@@YAHXZ'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entrylib.ll b/test/COFF/entrylib.ll
new file mode 100644 (file)
index 0000000..602b4ff
--- /dev/null
@@ -0,0 +1,12 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.obj %s
+; RUN: rm -f %t.lib
+; RUN: llvm-ar cru %t.lib %t.obj
+; RUN: lld-link /out:%t.exe /entry:main %t.lib
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @main() {
+  ret i32 0
+}
diff --git a/test/COFF/error-limit.test b/test/COFF/error-limit.test
new file mode 100644 (file)
index 0000000..3eebd12
--- /dev/null
@@ -0,0 +1,29 @@
+RUN: not lld-link 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 \
+RUN:   21 22 2>&1 | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT:      could not open 01
+DEFAULT:      could not open 20
+DEFAULT-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
+DEFAULT-NOT:  could not open 21
+
+RUN: not lld-link /ERRORLIMIT:5 01 02 03 04 05 06 07 08 09 10 2>&1 \
+RUN:   | FileCheck -check-prefix=LIMIT5 %s
+
+LIMIT5:      could not open 01
+LIMIT5:      could not open 05
+LIMIT5-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
+LIMIT5-NOT:  could not open 06
+
+RUN: not lld-link /ERRORLIMIT:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
+RUN:   16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=UNLIMITED %s
+
+UNLIMITED:     could not open 01
+UNLIMITED:     could not open 20
+UNLIMITED:     could not open 21
+UNLIMITED:     could not open 22
+UNLIMITED-NOT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
+
+RUN: not lld-link /ERRORLIMIT:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \
+RUN:   15 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=WRONG %s
+
+WRONG:      /ERRORLIMIT: number expected, but got XYZ
diff --git a/test/COFF/export-exe.test b/test/COFF/export-exe.test
new file mode 100644 (file)
index 0000000..6d60ce4
--- /dev/null
@@ -0,0 +1,10 @@
+# RUN: lld-link /entry:main /out:%t.exe /subsystem:windows \
+# RUN:   %p/Inputs/ret42.obj /export:main
+# RUN: llvm-objdump -p %t.exe | FileCheck %s
+
+CHECK:      Export Table:
+CHECK-NEXT: DLL name: export-exe.test.tmp.exe
+CHECK-NEXT: Ordinal base: 0
+CHECK-NEXT: Ordinal      RVA  Name
+CHECK-NEXT:       0        0
+CHECK-NEXT:       1   0x1000  main
diff --git a/test/COFF/export.test b/test/COFF/export.test
new file mode 100644 (file)
index 0000000..e4a094c
--- /dev/null
@@ -0,0 +1,92 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+#
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1:      Export Table:
+CHECK1:      DLL name: export.test.tmp.dll
+CHECK1:      Ordinal      RVA  Name
+CHECK1-NEXT:       0        0
+CHECK1-NEXT:       1   0x1008  exportfn1
+CHECK1-NEXT:       2   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2:      Export Table:
+CHECK2:      DLL name: export.test.tmp.dll
+CHECK2:      Ordinal      RVA  Name
+CHECK2-NEXT:       0        0
+CHECK2-NEXT:       1        0
+CHECK2-NEXT:       2        0
+CHECK2-NEXT:       3        0
+CHECK2-NEXT:       4        0
+CHECK2-NEXT:       5   0x1008  exportfn1
+CHECK2-NEXT:       6   0x1010  exportfn2
+CHECK2-NEXT:       7   0x1010  exportfn3
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
+
+CHECK3:      Export Table:
+CHECK3:      DLL name: export.test.tmp.dll
+CHECK3:      Ordinal      RVA  Name
+CHECK3-NEXT:       0        0
+CHECK3-NEXT:       1        0
+CHECK3-NEXT:       2        0
+CHECK3-NEXT:       3        0
+CHECK3-NEXT:       4        0
+CHECK3-NEXT:       5   0x1008
+CHECK3-NEXT:       6   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s
+
+CHECK4:      Export Table:
+CHECK4:      DLL name: export.test.tmp.dll
+CHECK4:      Ordinal      RVA  Name
+CHECK4-NEXT:       0        0
+CHECK4-NEXT:       1   0x1010  exportfn3
+CHECK4-NEXT:       2   0x1008  f1
+CHECK4-NEXT:       3   0x1010  f2
+
+# RUN: echo "EXPORTS exportfn1 @3" > %t.def
+# RUN: echo "fn2=exportfn2 @2" >> %t.def
+# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s
+
+CHECK5:      Export Table:
+CHECK5:      DLL name: export.test.tmp.dll
+CHECK5:      Ordinal      RVA  Name
+CHECK5-NEXT:       0        0
+CHECK5-NEXT:       1        0
+CHECK5-NEXT:       2   0x1010  fn2
+CHECK5-NEXT:       3   0x1008  exportfn1
+CHECK5-NEXT:       4   0x1010  exportfn3
+
+# RUN: lld-link /out:%t.DLL /dll %t.obj /export:exportfn1 /export:exportfn2 \
+# RUN:   /export:exportfn1 /export:exportfn2,@5 >& %t.log
+# RUN: FileCheck -check-prefix=CHECK6 %s < %t.log
+
+CHECK6:     duplicate /export option: exportfn2
+CHECK6-NOT: duplicate /export option: exportfn1
+
+# RUN: llvm-nm -M %t.lib | FileCheck --check-prefix=SYMTAB %s
+
+SYMTAB: __imp_exportfn1 in export.test.tmp.DLL
+SYMTAB: exportfn1 in export.test.tmp.DLL
+SYMTAB: __imp_exportfn2 in export.test.tmp.DLL
+SYMTAB: exportfn2 in export.test.tmp.DLL
+SYMTAB: __imp_exportfn3 in export.test.tmp.DLL
+SYMTAB: exportfn3 in export.test.tmp.DLL
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=kernel32.foobar
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=FORWARDER %s
+
+FORWARDER: Export Table:
+FORWARDER:  DLL name: export.test.tmp.dll
+FORWARDER:  Ordinal base: 0
+FORWARDER:  Ordinal      RVA  Name
+FORWARDER:        0        0
+FORWARDER:        1   0x1010  exportfn
+FORWARDER:        2           foo (forwarded to kernel32.foobar)
diff --git a/test/COFF/export32.test b/test/COFF/export32.test
new file mode 100644 (file)
index 0000000..83de18b
--- /dev/null
@@ -0,0 +1,142 @@
+# RUN: yaml2obj < %s > %t.obj
+#
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
+
+# CHECK1:      Export Table:
+# CHECK1:      DLL name: export32.test.tmp.dll
+# CHECK1:      Ordinal      RVA  Name
+# CHECK1-NEXT:       0        0
+# CHECK1-NEXT:       1   0x1008  exportfn1
+# CHECK1-NEXT:       2   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
+# RUN:   /export:exportfn2 /export:mangled
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK2:      Export Table:
+# CHECK2:      DLL name: export32.test.tmp.dll
+# CHECK2:      Ordinal      RVA  Name
+# CHECK2-NEXT:       0        0
+# CHECK2-NEXT:       1        0
+# CHECK2-NEXT:       2        0
+# CHECK2-NEXT:       3        0
+# CHECK2-NEXT:       4        0
+# CHECK2-NEXT:       5   0x1008  exportfn1
+# CHECK2-NEXT:       6   0x1010  exportfn2
+# CHECK2-NEXT:       7   0x1010  exportfn3
+# CHECK2-NEXT:       8   0x1010  mangled
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s
+
+# CHECK3:      Export Table:
+# CHECK3:      DLL name: export32.test.tmp.dll
+# CHECK3:      Ordinal      RVA  Name
+# CHECK3-NEXT:       0        0
+# CHECK3-NEXT:       1        0
+# CHECK3-NEXT:       2        0
+# CHECK3-NEXT:       3        0
+# CHECK3-NEXT:       4        0
+# CHECK3-NEXT:       5   0x1008
+# CHECK3-NEXT:       6   0x1010  exportfn2
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s
+
+# CHECK4:      Export Table:
+# CHECK4:      DLL name: export32.test.tmp.dll
+# CHECK4:      Ordinal      RVA  Name
+# CHECK4-NEXT:       0        0
+# CHECK4-NEXT:       1   0x1010  exportfn3
+# CHECK4-NEXT:       2   0x1008  f1
+# CHECK4-NEXT:       3   0x1010  f2
+
+# RUN: echo "EXPORTS exportfn1 @3" > %t.def
+# RUN: echo "fn2=exportfn2 @2" >> %t.def
+# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s
+
+# CHECK5:      Export Table:
+# CHECK5:      DLL name: export32.test.tmp.dll
+# CHECK5:      Ordinal      RVA  Name
+# CHECK5-NEXT:       0        0
+# CHECK5-NEXT:       1        0
+# CHECK5-NEXT:       2   0x1010  fn2
+# CHECK5-NEXT:       3   0x1008  exportfn1
+# CHECK5-NEXT:       4   0x1010  exportfn3
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
+# RUN:   /export:exportfn1 /export:exportfn2,@5 >& %t.log
+# RUN: FileCheck -check-prefix=CHECK6 %s < %t.log
+
+# CHECK6:     duplicate /export option: _exportfn2
+# CHECK6-NOT: duplicate /export option: _exportfn1
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=mangled
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK7 %s
+
+# CHECK7:      Export Table:
+# CHECK7:      DLL name: export32.test.tmp.dll
+# CHECK7:      Ordinal      RVA  Name
+# CHECK7-NEXT:       0        0
+# CHECK7-NEXT:       1        0
+# CHECK7-NEXT:       2   0x1010  foo
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B800000000506800000000680000000050E80000000050E800000000
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f6578706f72743a5f6578706f7274666e3300  # /export:_exportfn3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            __DllMainCRTStartup@12
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _exportfn1
+    Value:           8
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _exportfn2@4
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _exportfn3
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?mangled@@YAHXZ'
+    Value:           16
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/failifmismatch.test b/test/COFF/failifmismatch.test
new file mode 100644 (file)
index 0000000..021d91b
--- /dev/null
@@ -0,0 +1,11 @@
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj
+
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1
+
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1
+
+# RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2
diff --git a/test/COFF/filetype.test b/test/COFF/filetype.test
new file mode 100644 (file)
index 0000000..e161910
--- /dev/null
@@ -0,0 +1,4 @@
+# Make sure input file type is detected by file magic and not by extension.
+
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.lib
+# RUN: lld-link /out:%t.exe /entry:main %t.lib
diff --git a/test/COFF/force.test b/test/COFF/force.test
new file mode 100644 (file)
index 0000000..80bd275
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: not lld-link /out:%t.exe /entry:main %t.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /force >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: .obj: undefined symbol: foo
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            foo
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/guardcf.test b/test/COFF/guardcf.test
new file mode 100644 (file)
index 0000000..4f99d70
--- /dev/null
@@ -0,0 +1,74 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:main /out:%t.exe %t.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_fids_count
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_fids_table
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_flags
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_iat_count
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_iat_table
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_longjmp_count
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_longjmp_table
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/heap.test b/test/COFF/heap.test
new file mode 100644 (file)
index 0000000..1eb70a2
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT: SizeOfHeapReserve: 1048576
+DEFAULT: SizeOfHeapCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main /heap:0x3000 %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+# RUN: echo "HEAPSIZE 12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: SizeOfHeapReserve: 12288
+CHECK1: SizeOfHeapCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main /heap:0x5000,0x3000 %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+# RUN: echo "HEAPSIZE 20480,12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: SizeOfHeapReserve: 20480
+CHECK2: SizeOfHeapCommit: 12288
diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test
new file mode 100644 (file)
index 0000000..e987bb9
--- /dev/null
@@ -0,0 +1,132 @@
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /out:%t.exe /appcontainer
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+
+HEADER:      Format: COFF-i386
+HEADER-NEXT: Arch: i386
+HEADER-NEXT: AddressSize: 32bit
+HEADER-NEXT: ImageFileHeader {
+HEADER-NEXT:   Machine: IMAGE_FILE_MACHINE_I386 (0x14C)
+HEADER-NEXT:   SectionCount: 4
+HEADER-NEXT:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+HEADER-NEXT:   PointerToSymbolTable: 0x0
+HEADER-NEXT:   SymbolCount: 0
+HEADER-NEXT:   OptionalHeaderSize: 224
+HEADER-NEXT:   Characteristics [ (0x102)
+HEADER-NEXT:     IMAGE_FILE_32BIT_MACHINE (0x100)
+HEADER-NEXT:     IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
+HEADER-NEXT:   ]
+HEADER-NEXT: }
+HEADER-NEXT: ImageOptionalHeader {
+HEADER-NEXT:   Magic: 0x10B
+HEADER-NEXT:   MajorLinkerVersion: 14
+HEADER-NEXT:   MinorLinkerVersion: 0
+HEADER-NEXT:   SizeOfCode: 512
+HEADER-NEXT:   SizeOfInitializedData: 1536
+HEADER-NEXT:   SizeOfUninitializedData: 0
+HEADER-NEXT:   AddressOfEntryPoint: 0x2000
+HEADER-NEXT:   BaseOfCode: 0x2000
+HEADER-NEXT:   BaseOfData: 0x0
+HEADER-NEXT:   ImageBase: 0x400000
+HEADER-NEXT:   SectionAlignment: 4096
+HEADER-NEXT:   FileAlignment: 512
+HEADER-NEXT:   MajorOperatingSystemVersion: 6
+HEADER-NEXT:   MinorOperatingSystemVersion: 0
+HEADER-NEXT:   MajorImageVersion: 0
+HEADER-NEXT:   MinorImageVersion: 0
+HEADER-NEXT:   MajorSubsystemVersion: 6
+HEADER-NEXT:   MinorSubsystemVersion: 0
+HEADER-NEXT:   SizeOfImage: 16896
+HEADER-NEXT:   SizeOfHeaders: 512
+HEADER-NEXT:   Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
+HEADER-NEXT:   Characteristics [ (0x9940)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_NO_BIND (0x800)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
+HEADER-NEXT:     IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
+HEADER-NEXT:   ]
+HEADER-NEXT:   SizeOfStackReserve: 1048576
+HEADER-NEXT:   SizeOfStackCommit: 4096
+HEADER-NEXT:   SizeOfHeapReserve: 1048576
+HEADER-NEXT:   SizeOfHeapCommit: 4096
+HEADER-NEXT:   NumberOfRvaAndSize: 16
+HEADER-NEXT:   DataDirectory {
+HEADER-NEXT:     ExportTableRVA: 0x0
+HEADER-NEXT:     ExportTableSize: 0x0
+HEADER-NEXT:     ImportTableRVA: 0x3000
+HEADER-NEXT:     ImportTableSize: 0x28
+HEADER-NEXT:     ResourceTableRVA: 0x0
+HEADER-NEXT:     ResourceTableSize: 0x0
+HEADER-NEXT:     ExceptionTableRVA: 0x0
+HEADER-NEXT:     ExceptionTableSize: 0x0
+HEADER-NEXT:     CertificateTableRVA: 0x0
+HEADER-NEXT:     CertificateTableSize: 0x0
+HEADER-NEXT:     BaseRelocationTableRVA: 0x4000
+HEADER-NEXT:     BaseRelocationTableSize: 0x10
+HEADER-NEXT:     DebugRVA: 0x0
+HEADER-NEXT:     DebugSize: 0x0
+HEADER-NEXT:     ArchitectureRVA: 0x0
+HEADER-NEXT:     ArchitectureSize: 0x0
+HEADER-NEXT:     GlobalPtrRVA: 0x0
+HEADER-NEXT:     GlobalPtrSize: 0x0
+HEADER-NEXT:     TLSTableRVA: 0x0
+HEADER-NEXT:     TLSTableSize: 0x0
+HEADER-NEXT:     LoadConfigTableRVA: 0x0
+HEADER-NEXT:     LoadConfigTableSize: 0x0
+HEADER-NEXT:     BoundImportRVA: 0x0
+HEADER-NEXT:     BoundImportSize: 0x0
+HEADER-NEXT:     IATRVA: 0x3034
+HEADER-NEXT:     IATSize: 0xC
+HEADER-NEXT:     DelayImportDescriptorRVA: 0x0
+HEADER-NEXT:     DelayImportDescriptorSize: 0x0
+HEADER-NEXT:     CLRRuntimeHeaderRVA: 0x0
+HEADER-NEXT:     CLRRuntimeHeaderSize: 0x0
+HEADER-NEXT:     ReservedRVA: 0x0
+HEADER-NEXT:     ReservedSize: 0x0
+HEADER-NEXT:   }
+HEADER-NEXT: }
+HEADER-NEXT: DOSHeader {
+HEADER-NEXT:   Magic: MZ
+HEADER-NEXT:   UsedBytesInTheLastPage: 0
+HEADER-NEXT:   FileSizeInPages: 0
+HEADER-NEXT:   NumberOfRelocationItems: 0
+HEADER-NEXT:   HeaderSizeInParagraphs: 0
+HEADER-NEXT:   MinimumExtraParagraphs: 0
+HEADER-NEXT:   MaximumExtraParagraphs: 0
+HEADER-NEXT:   InitialRelativeSS: 0
+HEADER-NEXT:   InitialSP: 0
+HEADER-NEXT:   Checksum: 0
+HEADER-NEXT:   InitialIP: 0
+HEADER-NEXT:   InitialRelativeCS: 0
+HEADER-NEXT:   AddressOfRelocationTable: 64
+HEADER-NEXT:   OverlayNumber: 0
+HEADER-NEXT:   OEMid: 0
+HEADER-NEXT:   OEMinfo: 0
+HEADER-NEXT:   AddressOfNewExeHeader: 64
+HEADER-NEXT: }
+
+IMPORTS: Format: COFF-i386
+IMPORTS: Arch: i386
+IMPORTS: AddressSize: 32bit
+IMPORTS: Import {
+IMPORTS:   Name: std32.dll
+IMPORTS:   ImportLookupTableRVA: 0x3028
+IMPORTS:   ImportAddressTableRVA: 0x3034
+IMPORTS:   Symbol: ExitProcess (0)
+IMPORTS:   Symbol: MessageBoxA (1)
+IMPORTS: }
+
+BASEREL: BaseReloc [
+BASEREL:   Entry {
+BASEREL:     Type: HIGHLOW
+BASEREL:     Address: 0x2005
+BASEREL:   }
+BASEREL:   Entry {
+BASEREL:     Type: HIGHLOW
+BASEREL:     Address: 0x200C
+BASEREL:   }
+BASEREL: ]
diff --git a/test/COFF/help.test b/test/COFF/help.test
new file mode 100644 (file)
index 0000000..d36fe6d
--- /dev/null
@@ -0,0 +1,3 @@
+# RUN: lld-link /help | FileCheck %s
+
+CHECK: OVERVIEW: LLVM Linker
diff --git a/test/COFF/icf-associative.test b/test/COFF/icf-associative.test
new file mode 100644 (file)
index 0000000..bfaeabb
--- /dev/null
@@ -0,0 +1,104 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /debug /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Selected foo
+# CHECK:   Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+
+  - Name:            '.debug_blah'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     0000000000000000000000000000
+
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+
+  - Name:            '.debug_blah'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+
+  - Name:            '.debug_blah'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+      Selection:       IMAGE_COMDAT_SELECT_ASSOCIATIVE
+
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+
+  - Name:            '.debug_blah'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+      Selection:       IMAGE_COMDAT_SELECT_ASSOCIATIVE
+
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+
+  - Name:            bar
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-circular.test b/test/COFF/icf-circular.test
new file mode 100644 (file)
index 0000000..c113566
--- /dev/null
@@ -0,0 +1,81 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Selected foo
+# CHECK:   Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  10
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  10
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_REL32
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-circular2.test b/test/COFF/icf-circular2.test
new file mode 100644 (file)
index 0000000..3b8eb8f
--- /dev/null
@@ -0,0 +1,69 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Selected foo
+# CHECK:   Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+    Relocations:
+      - VirtualAddress:  5
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-data.test b/test/COFF/icf-data.test
new file mode 100644 (file)
index 0000000..20bdeca
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK-NOT: Removed foo
+# CHECK-NOT: Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-different-align.test b/test/COFF/icf-different-align.test
new file mode 100644 (file)
index 0000000..3502ed3
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK-NOT: Selected foo
+# CHECK-NOT:   Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       8
+    SectionData:     4883EC28E8000000004883C428C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/icf-local.test b/test/COFF/icf-local.test
new file mode 100644 (file)
index 0000000..db690b8
--- /dev/null
@@ -0,0 +1,66 @@
+# COMDAT sections with non-external linkage should not be merged by ICF.
+
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: sed s/foo/main/ %s | yaml2obj > %t2.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /verbose \
+# RUN:   %t1.obj %t2.obj > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK-NOT: Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     488D0500000000C3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      bar
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+    Alignment:       8
+    SectionData:     2A000000000000002B00000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1092178131
+      Number:          1
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          16
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1200668497
+      Number:          5
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/icf-simple.test b/test/COFF/icf-simple.test
new file mode 100644 (file)
index 0000000..c302c87
--- /dev/null
@@ -0,0 +1,71 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ICF %s < %t.log
+
+# ICF: Selected foo
+# ICF:   Removed bar
+
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose /opt:noicf %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=NOICF %s < %t.log
+# RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \
+# RUN:   /verbose /opt:noref,noicf %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=NOICF %s < %t.log
+
+# NOICF-NOT: Removed foo
+# NOICF-NOT: Removed bar
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     4883EC28E8000000004883C428C3
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          14
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1682752513
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/implib-name.test b/test/COFF/implib-name.test
new file mode 100644 (file)
index 0000000..81b5b25
--- /dev/null
@@ -0,0 +1,71 @@
+# RUN: mkdir -p %T
+# RUN: llvm-mc -triple x86_64-unknown-windows-msvc -filetype obj -o %T/object.obj %S/Inputs/object.s
+
+# RUN: lld-link /dll /machine:x64 /def:%S/Inputs/named.def /out:%T/library.dll %T/object.obj /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/library.lib | FileCheck %s -check-prefix CHECK-DEFAULT-DLL-EXT
+
+# RUN: lld-link /machine:x64 /def:%S/Inputs/named.def /out:%T/library.lib
+# RUN: llvm-ar t %T/library.lib | FileCheck %s -check-prefix CHECK-DEFAULT-DLL-EXT
+
+CHECK-DEFAULT-DLL-EXT: library.dll
+CHECK-DEFAULT-DLL-EXT: library.dll
+CHECK-DEFAULT-DLL-EXT: library.dll
+CHECK-DEFAULT-DLL-EXT: library.dll
+
+# RUN: lld-link /machine:x64 /def:%S/Inputs/named.def /out:%T/library.exe %T/object.obj /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/library.lib | FileCheck %s -check-prefix CHECK-DEFAULT-EXE-EXT
+
+CHECK-DEFAULT-EXE-EXT: library.exe
+CHECK-DEFAULT-EXE-EXT: library.exe
+CHECK-DEFAULT-EXE-EXT: library.exe
+CHECK-DEFAULT-EXE-EXT: library.exe
+
+# RUN: lld-link /dll /machine:x64 /def:%S/Inputs/extension.def /out:%T/extension.dll /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/extension.lib | FileCheck %s -check-prefix CHECK-EXTENSION
+
+# RUN: lld-link /machine:x64 /def:%S/Inputs/extension.def /out:%T/extension.exe /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/extension.lib | FileCheck %s -check-prefix CHECK-EXTENSION
+
+# RUN: lld-link /machine:x64 /def:%S/Inputs/extension.def /out:%T/extension.lib
+# RUN: llvm-ar t %T/extension.lib | FileCheck %s -check-prefix CHECK-EXTENSION
+
+CHECK-EXTENSION: library.ext
+CHECK-EXTENSION: library.ext
+CHECK-EXTENSION: library.ext
+CHECK-EXTENSION: library.ext
+
+# RUN: lld-link /dll /machine:x64 /def:%S/Inputs/default.def /out:%T/default.dll /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-OUTPUT-NAME-DLL
+
+# RUN: lld-link /machine:x64 /def:%S/Inputs/default.def /out:%T/default.lib
+# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-OUTPUT-NAME-DLL
+
+CHECK-OUTPUT-NAME-DLL: default.dll
+CHECK-OUTPUT-NAME-DLL: default.dll
+CHECK-OUTPUT-NAME-DLL: default.dll
+CHECK-OUTPUT-NAME-DLL: default.dll
+
+# RUN: lld-link /machine:x64 /def:%S/Inputs/default.def /out:%T/default.exe %T/object.obj /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-OUTPUT-NAME-EXE
+
+CHECK-OUTPUT-NAME-EXE: default.exe
+CHECK-OUTPUT-NAME-EXE: default.exe
+CHECK-OUTPUT-NAME-EXE: default.exe
+CHECK-OUTPUT-NAME-EXE: default.exe
+
+# RUN: lld-link /machine:x64 /out:%T/default.exe %T/object.obj /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-NODEF-EXE
+
+CHECK-NODEF-EXE: default.exe
+CHECK-NODEF-EXE: default.exe
+CHECK-NODEF-EXE: default.exe
+CHECK-NODEF-EXE: default.exe
+
+# RUN: lld-link /machine:x64 /dll /out:%T/default.dll %T/object.obj /entry:f /subsystem:CONSOLE
+# RUN: llvm-ar t %T/default.lib | FileCheck %s -check-prefix CHECK-NODEF-DLL
+
+CHECK-NODEF-DLL: default.dll
+CHECK-NODEF-DLL: default.dll
+CHECK-NODEF-DLL: default.dll
+CHECK-NODEF-DLL: default.dll
+
diff --git a/test/COFF/imports-mangle.test b/test/COFF/imports-mangle.test
new file mode 100644 (file)
index 0000000..5d8ccae
--- /dev/null
@@ -0,0 +1,66 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /opt:noref /entry:main \
+# RUN:   %t.obj %p/Inputs/imports-mangle.lib
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
+
+# CHECK: Import {
+# CHECK:   Symbol: sym4 (0)
+# CHECK:   Symbol: _sym3 (1)
+# CHECK:   Symbol: sym1 (2)
+# CHECK:   Symbol:  (2)
+# CHECK: }
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            sym1
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            sym2
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __sym3
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?sym4@@YAHH@Z'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/imports.test b/test/COFF/imports.test
new file mode 100644 (file)
index 0000000..326bfbe
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# Verify that the lld can handle .lib files and emit .idata sections.
+#
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   %p/Inputs/hello64.obj %p/Inputs/std64.lib
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   %p/Inputs/hello64.obj %p/Inputs/std64.lib /include:ExitProcess
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+
+TEXT: Disassembly of section .text:
+TEXT-NEXT: .text:
+TEXT-NEXT: subq    $40, %rsp
+TEXT-NEXT: movq    $0, %rcx
+TEXT-NEXT: leaq    -4108(%rip), %rdx
+TEXT-NEXT: leaq    -4121(%rip), %r8
+TEXT-NEXT: movl    $0, %r9d
+TEXT-NEXT: callq   60
+TEXT-NEXT: movl    $0, %ecx
+TEXT-NEXT: callq   18
+TEXT-NEXT: callq   29
+TEXT:      jmpq    *4098(%rip)
+TEXT:      jmpq    *4090(%rip)
+TEXT:      jmpq    *4082(%rip)
+
+IMPORT:      Import {
+IMPORT-NEXT:   Name: std64.dll
+IMPORT-NEXT:   ImportLookupTableRVA: 0x3028
+IMPORT-NEXT:   ImportAddressTableRVA: 0x3048
+IMPORT-NEXT:   Symbol: ExitProcess (0)
+IMPORT-NEXT:   Symbol:  (50)
+IMPORT-NEXT:   Symbol: MessageBoxA (1)
+IMPORT-NEXT: }
diff --git a/test/COFF/include-lto.ll b/test/COFF/include-lto.ll
new file mode 100644 (file)
index 0000000..d5ae546
--- /dev/null
@@ -0,0 +1,22 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /dll /out:%t.dll %t.obj
+; RUN: llvm-objdump -d %t.dll | FileCheck %s
+
+; Checks that code for foo is emitted, as required by the /INCLUDE directive.
+; CHECK: xorl %eax, %eax
+; CHECK-NEXT: retq
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @_DllMainCRTStartup() {
+  ret void
+}
+
+define i32 @foo() {
+  ret i32 0
+}
+
+!llvm.linker.options = !{!0}
+!0 = !{!"/INCLUDE:foo"}
diff --git a/test/COFF/include.test b/test/COFF/include.test
new file mode 100644 (file)
index 0000000..e7b0c58
--- /dev/null
@@ -0,0 +1,83 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /verbose >& %t.log
+### FileCheck doesn't like empty input, so write something.
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /verbose /include:unused >& %t.log
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+# CHECK1:     Discarded unused
+# CHECK1-NOT: Discarded used
+# CHECK2-NOT: Discarded unused
+# CHECK2-NOT: Discarded used
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2f696e636c7564653a7573656400  # /include:used
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            used
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            unused
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/include2.test b/test/COFF/include2.test
new file mode 100644 (file)
index 0000000..528a273
--- /dev/null
@@ -0,0 +1,14 @@
+# RUN: yaml2obj < %p/Inputs/include1a.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/include1b.yaml > %t2.obj
+# RUN: yaml2obj < %p/Inputs/include1c.yaml > %t3.obj
+# RUN: rm -f %t2.lib %t3.lib
+# RUN: llvm-ar cru %t2.lib %t2.obj
+# RUN: llvm-ar cru %t3.lib %t3.obj
+# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.lib %t3.lib /verbose >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: include2.test.tmp1.obj
+CHECK: include2.test.tmp2.lib
+CHECK: include2.test.tmp2.lib(include2.test.tmp2.obj) for foo
+CHECK: include2.test.tmp3.lib
+CHECK: include2.test.tmp3.lib(include2.test.tmp3.obj) for bar
diff --git a/test/COFF/internal.test b/test/COFF/internal.test
new file mode 100644 (file)
index 0000000..bc958cb
--- /dev/null
@@ -0,0 +1,42 @@
+# Test that non-external symbols don't conflict
+
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %s > %t2.obj
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t3.obj
+# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.obj %t3.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            defined
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            absolute
+    Value:           0xdeadbeef
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/COFF/invalid-debug-type.test b/test/COFF/invalid-debug-type.test
new file mode 100644 (file)
index 0000000..1026418
--- /dev/null
@@ -0,0 +1,5 @@
+# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
+# RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
+# RUN:   %t1.obj %t2.obj
+
diff --git a/test/COFF/invalid-obj.test b/test/COFF/invalid-obj.test
new file mode 100644 (file)
index 0000000..6f76c37
--- /dev/null
@@ -0,0 +1,14 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: not lld-link %t.obj 2>&1 | FileCheck %s
+
+# CHECK: getSectionName failed: #1:
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '/1'
+    Characteristics: []
+    SectionData:     00
+symbols:
diff --git a/test/COFF/largeaddressaware.test b/test/COFF/largeaddressaware.test
new file mode 100644 (file)
index 0000000..d035e7c
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /out:%t.exe /largeaddressaware
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+
+HEADER:      Format: COFF-i386
+HEADER-NEXT: Arch: i386
+HEADER-NEXT: AddressSize: 32bit
+HEADER-NEXT: ImageFileHeader {
+HEADER-NEXT:   Machine: IMAGE_FILE_MACHINE_I386 (0x14C)
+HEADER-NEXT:   SectionCount: 4
+HEADER-NEXT:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+HEADER-NEXT:   PointerToSymbolTable: 0x0
+HEADER-NEXT:   SymbolCount: 0
+HEADER-NEXT:   OptionalHeaderSize: 224
+HEADER-NEXT:   Characteristics [ (0x122)
+HEADER-NEXT:     IMAGE_FILE_32BIT_MACHINE (0x100)
+HEADER-NEXT:     IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
+HEADER-NEXT:     IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20)
+HEADER-NEXT:   ]
+HEADER-NEXT: }
diff --git a/test/COFF/lib.test b/test/COFF/lib.test
new file mode 100644 (file)
index 0000000..2d63ed6
--- /dev/null
@@ -0,0 +1,11 @@
+# RUN: lld-link /machine:x64 /def:%S/Inputs/library.def /out:%t.lib
+# RUN: llvm-nm %t.lib | FileCheck %s
+
+CHECK: 00000000 R __imp_constant
+CHECK: 00000000 R constant
+
+CHECK: 00000000 D __imp_data
+
+CHECK: 00000000 T __imp_function
+CHECK: 00000000 T function
+
diff --git a/test/COFF/libpath.test b/test/COFF/libpath.test
new file mode 100644 (file)
index 0000000..da465bc
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: mkdir -p %t/a %t/b %t/c
+# RUN: cp %p/Inputs/std64.lib %t/a/
+# RUN: cp %p/Inputs/std64.lib %t/b/
+# RUN: cp %p/Inputs/std64.lib %t/c/
+
+# RUN: env LIB=%t/a lld-link /out:%t.exe /entry:main /verbose \
+# RUN:   std64.lib /subsystem:console %p/Inputs/hello64.obj \
+# RUN:   /libpath:%t/b /libpath:%t/c > %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+CHECK1: b{{[/\\]}}std64.lib
+
+# RUN: lld-link /out:%t.exe /entry:main /verbose \
+# RUN:   std64.lib /subsystem:console %p/Inputs/hello64.obj \
+# RUN:   /libpath:%t/a /libpath:%t/b /libpath:%t/c > %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+CHECK2: a{{[/\\]}}std64.lib
diff --git a/test/COFF/linkenv.test b/test/COFF/linkenv.test
new file mode 100644 (file)
index 0000000..6033094
--- /dev/null
@@ -0,0 +1,4 @@
+# RUN: env LINK=-help lld-link | FileCheck %s
+# RUN: env _LINK_=-help lld-link | FileCheck %s
+
+CHECK: OVERVIEW: LLVM Linker
diff --git a/test/COFF/linkrepro.test b/test/COFF/linkrepro.test
new file mode 100644 (file)
index 0000000..8f42234
--- /dev/null
@@ -0,0 +1,37 @@
+# REQUIRES: x86, shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build1 %t.dir/build2 %t.dir/build3
+# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
+
+# RUN: cd %t.dir/build1
+# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \
+# RUN:   /entry:main@0 /linkrepro:. /out:%t.exe
+# RUN: tar xf repro.tar
+# RUN: diff %t.obj repro/%:t.obj
+# RUN: diff %p/Inputs/std32.lib repro/%:p/Inputs/std32.lib
+# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
+
+# RUN: cd %t.dir/build2
+# RUN: lld-link %t.obj /libpath:%p/Inputs /defaultlib:std32 /subsystem:console \
+# RUN:   /entry:main@0 /linkrepro:. /out:%t.exe
+# RUN: tar xf repro.tar
+# RUN: diff %t.obj repro/%:t.obj
+# RUN: diff %p/Inputs/std32.lib repro/%:p/Inputs/std32.lib
+# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
+
+# RUN: cd %t.dir/build3
+# RUN: env LIB=%p/Inputs lld-link %t.obj /defaultlib:std32 /subsystem:console \
+# RUN:   /entry:main@0 /linkrepro:. /out:%t.exe
+# RUN: tar xf repro.tar
+# RUN: diff %t.obj repro/%:t.obj
+# RUN: diff %p/Inputs/std32.lib repro/%:p/Inputs/std32.lib
+# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
+
+# RSP: /subsystem:console
+# RSP: /entry:main@0
+# RSP-NOT: /linkrepro:
+# RSP: /out:
+# RSP: linkrepro.test.tmp.obj
+# RSP-NOT: defaultlib
+# RSP: std32.lib
diff --git a/test/COFF/lldmap.test b/test/COFF/lldmap.test
new file mode 100644 (file)
index 0000000..d705a16
--- /dev/null
@@ -0,0 +1,10 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /lldmap:%T/foo.map %t.obj
+# RUN: FileCheck -strict-whitespace %s < %T/foo.map
+# RUN: lld-link /out:%T/bar.exe /entry:main /lldmap %t.obj
+# RUN: FileCheck -strict-whitespace %s < %T/bar.map
+
+# CHECK:      Address  Size     Align Out     In      Symbol
+# CHECK-NEXT: 00001000 00000006  4096 .text
+# CHECK-NEXT: 00001000 00000006    16         {{.*}}lldmap.test.tmp.obj:(.text$mn)
+# CHECK-NEXT: 00001000 00000000     0                 main
diff --git a/test/COFF/loadcfg.ll b/test/COFF/loadcfg.ll
new file mode 100644 (file)
index 0000000..c49ae2f
--- /dev/null
@@ -0,0 +1,15 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
+; RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+; CHECK: LoadConfigTableRVA: 0x1000
+; CHECK: LoadConfigTableSize: 0x70
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+@_load_config_used = constant [28 x i32] [i32 112, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0]
+
+define void @main() {
+  ret void
+}
diff --git a/test/COFF/loadcfg.test b/test/COFF/loadcfg.test
new file mode 100644 (file)
index 0000000..b74917f
--- /dev/null
@@ -0,0 +1,75 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: LoadConfigTableRVA: 0x1000
+# CHECK: LoadConfigTableSize: 0x70
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     '70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .text
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          112
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            _load_config_used
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/loadcfg32.test b/test/COFF/loadcfg32.test
new file mode 100644 (file)
index 0000000..03a066c
--- /dev/null
@@ -0,0 +1,58 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: LoadConfigTableRVA: 0x1000
+# CHECK: LoadConfigTableSize: 0x40
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     '40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            .rdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          64
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            __load_config_used
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/locally-imported.test b/test/COFF/locally-imported.test
new file mode 100644 (file)
index 0000000..a10da4b
--- /dev/null
@@ -0,0 +1,61 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 1000 00200000
+# CHECK:      Contents of section .rdata:
+# CHECK-NEXT: 2000 04100040 01000000
+
+# BASEREL:      BaseReloc [
+# BASEREL-NEXT:   Entry {
+# BASEREL-NEXT:     Type: DIR64
+# BASEREL-NEXT:     Address: 0x2000
+# BASEREL-NEXT:   }
+# BASEREL-NEXT:   Entry {
+# BASEREL-NEXT:     Type: ABSOLUTE
+# BASEREL-NEXT:     Address: 0x2000
+# BASEREL-NEXT:   }
+# BASEREL-NEXT: ]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __imp_main
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp_main
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/locally-imported32.test b/test/COFF/locally-imported32.test
new file mode 100644 (file)
index 0000000..789c8c8
--- /dev/null
@@ -0,0 +1,50 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 1000 00200000
+
+# CHECK:      Contents of section .rdata:
+# CHECK-NEXT: 2000 04104000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      __imp__main
+        Type:            IMAGE_REL_I386_DIR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            _main
+    Value:           4
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp__main
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/long-section-name.test b/test/COFF/long-section-name.test
new file mode 100644 (file)
index 0000000..1de329d
--- /dev/null
@@ -0,0 +1,58 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+# CHECK: Name: .data_long_section_name
+# CHECK: Name: .text_long_section_name
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .text_long_section_name
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            .data_long_section_name
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     "00"
+symbols:
+  - Name:            "@comp.id"
+    Value:           10394907
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text_long_section_name
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data_long_section_name
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/lto-chkstk.ll b/test/COFF/lto-chkstk.ll
new file mode 100644 (file)
index 0000000..43b0bff
--- /dev/null
@@ -0,0 +1,17 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-foo.obj %S/Inputs/lto-chkstk-foo.s
+; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-chkstk.obj %S/Inputs/lto-chkstk-chkstk.s
+; RUN: llvm-ar cru %t.lib %T/lto-chkstk-chkstk.obj
+; RUN: lld-link /out:%t.exe /entry:main /subsystem:console %t.obj %T/lto-chkstk-foo.obj %t.lib
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @main() {
+entry:
+  %array4096 = alloca [4096 x i8]
+  call void @foo([4096 x i8]* %array4096)
+  ret void
+}
+
+declare void @foo([4096 x i8]*)
diff --git a/test/COFF/lto-comdat.ll b/test/COFF/lto-comdat.ll
new file mode 100644 (file)
index 0000000..b255f69
--- /dev/null
@@ -0,0 +1,108 @@
+; RUN: llvm-as -o %T/comdat-main.lto.obj %s
+; RUN: llvm-as -o %T/comdat1.lto.obj %S/Inputs/lto-comdat1.ll
+; RUN: llvm-as -o %T/comdat2.lto.obj %S/Inputs/lto-comdat2.ll
+; RUN: rm -f %T/comdat.lto.lib
+; RUN: llvm-ar cru %T/comdat.lto.lib %T/comdat1.lto.obj %T/comdat2.lto.obj
+
+; RUN: llc -filetype=obj -o %T/comdat-main.obj %s
+; RUN: llc -filetype=obj -o %T/comdat1.obj %S/Inputs/lto-comdat1.ll
+; RUN: llc -filetype=obj -o %T/comdat2.obj %S/Inputs/lto-comdat2.ll
+; RUN: rm -f %T/comdat.lib
+; RUN: llvm-ar cru %T/comdat.lib %T/comdat1.obj %T/comdat2.obj
+
+; Check that, when we use an LTO main with LTO objects, we optimize away all
+; of f1, f2, and comdat.
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lto.lib
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s
+
+; Check that, when we use a non-LTO main with LTO objects, we pick the comdat
+; implementation in LTO, elide calls to it from inside LTO, and retain the
+; call to comdat from main.
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat1.lto.obj %T/comdat2.lto.obj
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat.lto.lib
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s
+
+; Check that, when we use an LTO main with non-LTO objects, we pick the comdat
+; implementation in LTO, elide the call to it from inside LTO, and keep the
+; calls to comdat from the non-LTO objects.
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.obj %T/comdat2.obj
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s
+; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lib
+; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s
+
+; HEADERS-11: AddressOfEntryPoint: 0x1000
+; TEXT-11: Disassembly of section .text:
+; TEXT-11-NEXT: .text:
+; TEXT-11-NEXT: xorl   %eax, %eax
+; TEXT-11-NEXT: retq
+
+; HEADERS-01: AddressOfEntryPoint: 0x2000
+; TEXT-01: Disassembly of section .text:
+; TEXT-01-NEXT: .text:
+; TEXT-01-NEXT: subq   $40, %rsp
+; TEXT-01-NEXT: callq  39
+; TEXT-01-NEXT: callq  50
+; TEXT-01-NEXT: callq  13
+; TEXT-01-NEXT: xorl   %eax, %eax
+; TEXT-01-NEXT: addq   $40, %rsp
+; TEXT-01: retq
+; TEXT-01-NOT: callq
+; TEXT-01: retq
+; TEXT-01-NOT: callq
+; TEXT-01: retq
+; TEXT-01-NOT: callq
+; TEXT-01: retq
+; TEXT-01-NOT: {{.}}
+
+; HEADERS-10: AddressOfEntryPoint: 0x2020
+; TEXT-10: Disassembly of section .text:
+; TEXT-10-NEXT: .text:
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  55
+; TEXT-10-NEXT: nop
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  39
+; TEXT-10-NEXT: nop
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  -41
+; TEXT-10-NEXT: callq  -30
+; TEXT-10-NEXT: xorl   %eax, %eax
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+; TEXT-10-NOT: callq
+; TEXT-10: retq
+; TEXT-10-NOT: {{.}}
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$comdat = comdat any
+
+define i32 @main() {
+  call void @f1()
+  call void @f2()
+  call void @comdat()
+  ret i32 0
+}
+
+define linkonce_odr void @comdat() comdat {
+  ret void
+}
+
+declare void @f1()
+declare void @f2()
diff --git a/test/COFF/lto-debug-pass-arguments.ll b/test/COFF/lto-debug-pass-arguments.ll
new file mode 100644 (file)
index 0000000..4381590
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.obj
+; RUN: lld-link /dll /out:%t.dll %t.obj /mllvm:-debug-pass=Arguments 2>&1 | FileCheck %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @dummy() {
+  ret void
+}
+
+define void @_DllMainCRTStartup() {
+  ret void
+}
+
+; CHECK: Pass Arguments:
diff --git a/test/COFF/lto-lazy-reference.ll b/test/COFF/lto-lazy-reference.ll
new file mode 100644 (file)
index 0000000..22f9539
--- /dev/null
@@ -0,0 +1,21 @@
+; RUN: llc -mtriple=i686-pc-windows-msvc -filetype=obj -o %T/lto-lazy-reference-quadruple.obj %S/Inputs/lto-lazy-reference-quadruple.ll
+; RUN: llvm-as -o %T/lto-lazy-reference-dummy.bc %S/Inputs/lto-lazy-reference-dummy.ll
+; RUN: rm -f %t.lib
+; RUN: llvm-ar cru %t.lib %T/lto-lazy-reference-quadruple.obj %T/lto-lazy-reference-dummy.bc
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t.exe /entry:main /subsystem:console %t.obj %t.lib
+
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i686-pc-windows-msvc18.0.0"
+
+define double @main(double %x) {
+entry:
+  ; When compiled, this defines the __real@40800000 symbol, which already has a
+  ; lazy definition in the lib file from  lto-lazy-reference-quadruple.obj. This
+  ; test makes sure we *don't* try to take the definition from the lazy
+  ; reference, because that can bring in new references to bitcode files after
+  ; LTO, such as lto-lazy-reference-dummy.bc in this case.
+  %mul = fmul double %x, 4.0
+
+  ret double %mul
+}
diff --git a/test/COFF/lto-linker-opts.ll b/test/COFF/lto-linker-opts.ll
new file mode 100644 (file)
index 0000000..1d78875
--- /dev/null
@@ -0,0 +1,8 @@
+; RUN: llvm-as -o %T/lto-linker-opts.obj %s
+; RUN: env LIB=%S/Inputs lld-link /out:%T/lto-linker-opts.exe /entry:main /subsystem:console %T/lto-linker-opts.obj
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+!llvm.linker.options = !{!0}
+!0 = !{!"/DEFAULTLIB:ret42.lib"}
diff --git a/test/COFF/lto-new-symbol.ll b/test/COFF/lto-new-symbol.ll
new file mode 100644 (file)
index 0000000..d9e14eb
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t.exe /entry:foo /subsystem:console %t.obj
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo(<4 x i32>* %p, <4 x float>* %q, i1 %t) nounwind {
+entry:
+  br label %loop
+loop:
+  store <4 x i32><i32 1073741824, i32 1073741824, i32 1073741824, i32 1073741824>, <4 x i32>* %p
+  store <4 x float><float 2.0, float 2.0, float 2.0, float 2.0>, <4 x float>* %q
+  br i1 %t, label %loop, label %ret
+ret:
+  ret void
+}
diff --git a/test/COFF/lto-opt-level.ll b/test/COFF/lto-opt-level.ll
new file mode 100644 (file)
index 0000000..674b6cc
--- /dev/null
@@ -0,0 +1,21 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t0.exe /entry:main /subsystem:console /opt:lldlto=0 /debug %t.obj
+; RUN: llvm-nm %t0.exe | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: lld-link /out:%t2.exe /entry:main /subsystem:console /opt:lldlto=2 /debug %t.obj
+; RUN: llvm-nm %t2.exe | FileCheck --check-prefix=CHECK-O2 %s
+; RUN: lld-link /out:%t2a.exe /entry:main /subsystem:console /debug %t.obj
+; RUN: llvm-nm %t2a.exe | FileCheck --check-prefix=CHECK-O2 %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+; CHECK-O0: foo
+; CHECK-O2-NOT: foo
+define internal void @foo() {
+  ret void
+}
+
+define void @main() {
+  call void @foo()
+  ret void
+}
diff --git a/test/COFF/lto-parallel.ll b/test/COFF/lto-parallel.ll
new file mode 100644 (file)
index 0000000..449e3a0
--- /dev/null
@@ -0,0 +1,20 @@
+; RUN: llvm-as -o %t.obj %s
+; RUN: lld-link /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=2 /subsystem:console /lldmap:%t.map %t.obj
+; RUN: FileCheck %s < %t.map
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+; CHECK: lto.tmp
+; CHECK-NEXT: foo
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK: lto.tmp
+; CHECK: bar
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/COFF/lto.ll b/test/COFF/lto.ll
new file mode 100644 (file)
index 0000000..b8f8d70
--- /dev/null
@@ -0,0 +1,130 @@
+; RUN: llvm-as -o %T/main.lto.obj %s
+; RUN: llvm-as -o %T/foo.lto.obj %S/Inputs/lto-dep.ll
+; RUN: rm -f %T/foo.lto.lib
+; RUN: llvm-ar cru %T/foo.lto.lib %T/foo.lto.obj
+
+; RUN: llc -filetype=obj -o %T/main.obj %s
+; RUN: llc -filetype=obj -o %T/foo.obj %S/Inputs/lto-dep.ll
+; RUN: rm -f %T/foo.lib
+; RUN: llvm-ar cru %T/foo.lib %T/foo.obj
+
+; RUN: lld-link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.obj
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s
+; RUN: lld-link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.lib /verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s
+
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.obj
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.lib
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s
+
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.obj
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s
+; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.lib
+; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s
+; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s
+
+; VERBOSE: foo.lto.lib({{.*}}foo.lto.obj)
+
+; HEADERS-11: AddressOfEntryPoint: 0x1000
+; TEXT-11: Disassembly of section .text:
+; TEXT-11-NEXT: .text:
+; TEXT-11-NEXT: xorl   %eax, %eax
+; TEXT-11-NEXT: retq
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: int3
+; TEXT-11-NEXT: movl   $2, %eax
+; TEXT-11-NEXT: retq
+
+; HEADERS-01: AddressOfEntryPoint: 0x2000
+; TEXT-01: Disassembly of section .text:
+; TEXT-01-NEXT: .text:
+; TEXT-01-NEXT: subq   $40, %rsp
+; TEXT-01-NEXT: callq  23
+; TEXT-01-NEXT: xorl   %eax, %eax
+; TEXT-01-NEXT: addq   $40, %rsp
+; TEXT-01-NEXT: retq
+; TEXT-01-NEXT: retq
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: int3
+; TEXT-01-NEXT: retq
+
+; HEADERS-10: AddressOfEntryPoint: 0x2020
+; TEXT-10: Disassembly of section .text:
+; TEXT-10-NEXT: .text:
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: nopw    %cs:(%rax,%rax)
+; TEXT-10-NEXT: retq
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: int3
+; TEXT-10-NEXT: subq   $40, %rsp
+; TEXT-10-NEXT: callq  -41
+; TEXT-10-NEXT: xorl   %eax, %eax
+; TEXT-10-NEXT: addq   $40, %rsp
+; TEXT-10-NEXT: retq
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @main() {
+  call void @foo()
+  ret i32 0
+}
+
+declare void @foo()
+
+$f1 = comdat any
+define i32 @f1() comdat($f1) {
+  ret i32 1
+}
+
+$f2 = comdat any
+define i32 @f2() comdat($f2) {
+  ret i32 2
+}
+
+define internal void @internal() {
+  ret void
+}
diff --git a/test/COFF/machine.test b/test/COFF/machine.test
new file mode 100644 (file)
index 0000000..847018f
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s
+# RUN: lld-link /entry:main /subsystem:console /machine:x64 \
+# RUN:   /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s
+
+AMD64: Machine: IMAGE_FILE_MACHINE_AMD64
+
+# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t.obj
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s
+# RUN: lld-link /entry:main /subsystem:console /machine:x86 \
+# RUN:   /out:%t.exe %t.obj /fixed
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s
+
+I386: Machine: IMAGE_FILE_MACHINE_I386
+
+# RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj
+# RUN: not lld-link /entry:main /subsystem:console /machine:x86 \
+# RUN:   /out:%t.exe %t.obj /fixed >& %t.log
+# RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log
+
+# RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t1.obj
+# RUN: sed -e s/main/foo/ %p/Inputs/machine-x64.yaml | yaml2obj > %t2.obj
+# RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \
+# RUN:   %t1.obj %t2.obj >& %t.log
+# RUN: FileCheck -check-prefix=INCOMPAT %s < %t.log
+
+INCOMPAT: .obj: machine type x64 conflicts with x86
diff --git a/test/COFF/manifest.test b/test/COFF/manifest.test
new file mode 100644 (file)
index 0000000..accec48
--- /dev/null
@@ -0,0 +1,66 @@
+# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: rm -f %t.exe.manifest
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: test ! -e %t.exe.manifest
+
+# RUN: lld-link /manifest /out:%t.exe /entry:main %t.obj
+# RUN: FileCheck -check-prefix=MANIFEST %s < %t.exe.manifest
+
+MANIFEST: <?xml version="1.0" standalone="yes"?>
+MANIFEST: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+MANIFEST:           manifestVersion="1.0">
+MANIFEST:   <trustInfo>
+MANIFEST:     <security>
+MANIFEST:       <requestedPrivileges>
+MANIFEST:          <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
+MANIFEST:       </requestedPrivileges>
+MANIFEST:     </security>
+MANIFEST:   </trustInfo>
+MANIFEST: </assembly>
+
+# RUN: lld-link /out:%t.exe /entry:main /manifest \
+# RUN:   /manifestuac:"level='requireAdministrator' uiAccess='true'" %t.obj
+# RUN: FileCheck -check-prefix=UAC %s < %t.exe.manifest
+
+UAC: <?xml version="1.0" standalone="yes"?>
+UAC: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+UAC:           manifestVersion="1.0">
+UAC:   <trustInfo>
+UAC:     <security>
+UAC:       <requestedPrivileges>
+UAC:          <requestedExecutionLevel level='requireAdministrator' uiAccess='true'/>
+UAC:       </requestedPrivileges>
+UAC:     </security>
+UAC:   </trustInfo>
+UAC: </assembly>
+
+# /manifestdependency implies /manifest. (/manifestuac doesn't.)
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   /manifestdependency:"foo='bar'" %t.obj
+# RUN: FileCheck -check-prefix=DEPENDENCY %s < %t.exe.manifest
+
+DEPENDENCY: <?xml version="1.0" standalone="yes"?>
+DEPENDENCY: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+DEPENDENCY:           manifestVersion="1.0">
+DEPENDENCY:   <trustInfo>
+DEPENDENCY:     <security>
+DEPENDENCY:       <requestedPrivileges>
+DEPENDENCY:          <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
+DEPENDENCY:       </requestedPrivileges>
+DEPENDENCY:     </security>
+DEPENDENCY:   </trustInfo>
+DEPENDENCY:   <dependency>
+DEPENDENCY:     <dependentAssembly>
+DEPENDENCY:       <assemblyIdentity foo='bar' />
+DEPENDENCY:     </dependentAssembly>
+DEPENDENCY:   </dependency>
+DEPENDENCY: </assembly>
+
+# RUN: lld-link /manifest /out:%t.exe /entry:main /manifestuac:no %t.obj
+# RUN: FileCheck -check-prefix=NOUAC %s < %t.exe.manifest
+
+NOUAC: <?xml version="1.0" standalone="yes"?>
+NOUAC: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+NOUAC:           manifestVersion="1.0">
+NOUAC: </assembly>
diff --git a/test/COFF/manifestinput.test b/test/COFF/manifestinput.test
new file mode 100644 (file)
index 0000000..95ebc22
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: win_mt
+
+# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   /manifest:embed \
+# RUN:   /manifestuac:"level='requireAdministrator'" \
+# RUN:   /manifestinput:%p/Inputs/manifestinput.test %t.obj
+# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \
+# RUN:   -check-prefix TEST_EMBED
+
+TEST_EMBED:          ResourceTableRVA: 0x1000
+TEST_EMBED-NEXT:     ResourceTableSize: 0x298
+TEST_EMBED-DAG:      Resources [
+TEST_EMBED-NEXT:       Total Number of Resources: 1 
+TEST_EMBED-DAG:        Number of String Entries: 0
+TEST_EMBED-NEXT:       Number of ID Entries: 1
+TEST_EMBED-NEXT:       Type: kRT_MANIFEST (ID 24) [
+TEST_EMBED-NEXT:         Table Offset: 0x18
+TEST_EMBED-NEXT:         Number of String Entries: 0
+TEST_EMBED-NEXT:         Number of ID Entries: 1
+TEST_EMBED-NEXT:         Name: (ID 1) [
+TEST_EMBED-NEXT:           Table Offset: 0x30
+TEST_EMBED-NEXT:           Number of String Entries: 0
+TEST_EMBED-NEXT:           Number of ID Entries: 1
+TEST_EMBED-NEXT:           Language: (ID 1033) [
+TEST_EMBED-NEXT:             Entry Offset: 0x48
diff --git a/test/COFF/merge.test b/test/COFF/merge.test
new file mode 100644 (file)
index 0000000..4b5c100
--- /dev/null
@@ -0,0 +1,53 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /merge:.foo=.abc /merge:.bar=.def %t.obj /debug
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+# CHECK: Name: .def
+# CHECK: Name: .abc
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .foo
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     000000000000
+  - Name:            .bar
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .bar
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/msvclto-archive.ll b/test/COFF/msvclto-archive.ll
new file mode 100644 (file)
index 0000000..334565a
--- /dev/null
@@ -0,0 +1,40 @@
+; REQUIRES: x86
+;; Make sure we re-create archive files to strip bitcode files.
+
+;; Do not create empty archives because the MSVC linker
+;; doesn't support them.
+; RUN: llvm-as -o %t.obj %s
+; RUN: rm -f %t-main1.a
+; RUN: llvm-ar cru %t-main1.a %t.obj
+; RUN: mkdir -p %t.dir
+; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t.dir/bitcode.obj %p/Inputs/msvclto.s
+; RUN: lld-link %t-main1.a %t.dir/bitcode.obj /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
+; RUN:   /entry:main /verbose > %t.log || true
+; RUN: FileCheck -check-prefix=BC %s < %t.log
+; BC-NOT: Creating a temporary archive for
+
+; RUN: rm -f %t-main2.a
+; RUN: llvm-ar cru %t-main2.a %t.dir/bitcode.obj
+; RUN: lld-link %t.obj %t-main2.a /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
+; RUN:   /entry:main /verbose > %t.log || true
+; RUN: FileCheck -check-prefix=OBJ %s < %t.log
+; OBJ-NOT: Creating a temporary archive
+
+;; Make sure that we always rebuild thin archives because
+;; the MSVC linker doesn't support thin archives.
+; RUN: rm -f %t-main3.a
+; RUN: llvm-ar cruT %t-main3.a %t.dir/bitcode.obj
+; RUN: lld-link %t.obj %t-main3.a /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
+; RUN:   /entry:main /verbose > %t.log || true
+; RUN: FileCheck -check-prefix=THIN %s < %t.log
+; THIN: Creating a temporary archive
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare void @foo()
+
+define i32 @main() {
+  call void @foo()
+  ret i32 0
+}
diff --git a/test/COFF/msvclto-order.ll b/test/COFF/msvclto-order.ll
new file mode 100644 (file)
index 0000000..6f569af
--- /dev/null
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: opt -thinlto-bc %s -o %t.obj
+; RUN: llc -filetype=obj %S/Inputs/msvclto-order-a.ll -o %T/msvclto-order-a.obj
+; RUN: llvm-ar crs %T/msvclto-order-a.lib %T/msvclto-order-a.obj
+; RUN: llc -filetype=obj %S/Inputs/msvclto-order-b.ll -o %T/msvclto-order-b.obj
+; RUN: llvm-ar crs %T/msvclto-order-b.lib %T/msvclto-order-b.obj
+; RUN: lld-link /verbose /msvclto /out:%t.exe /entry:main %t.obj \
+; RUN:     %T/msvclto-order-a.lib %T/msvclto-order-b.lib > %t.log || true
+; RUN: FileCheck %s < %t.log
+
+; CHECK: : link.exe
+; CHECK-NOT: .lib{{$}}
+; CHECK: lld-msvclto-order-a{{.*}}.obj
+; CHECK-NOT: lld-msvclto-order-b{{.*}}.obj
+; CHECK: .lib{{$}}
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare void @foo()
+
+define i32 @main() {
+  call void @foo()
+  ret i32 0
+}
diff --git a/test/COFF/msvclto.ll b/test/COFF/msvclto.ll
new file mode 100644 (file)
index 0000000..66fabeb
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.obj %s
+; RUN: mkdir -p %t.dir
+; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t.dir/bitcode.obj %p/Inputs/msvclto.s
+; RUN: lld-link %t.obj %t.dir/bitcode.obj /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
+; RUN:   /entry:main /verbose > %t.log || true
+; RUN: FileCheck %s < %t.log
+
+; CHECK: /opt:icf /entry:main
+; CHECK: /verbose
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare void @foo()
+
+define i32 @main() {
+  call void @foo()
+  ret i32 0
+}
diff --git a/test/COFF/nodefaultlib.test b/test/COFF/nodefaultlib.test
new file mode 100644 (file)
index 0000000..867dc8f
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: cp %p/Inputs/hello64.obj %T
+# RUN: cp %p/Inputs/std64.lib %T
+
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   hello64.obj /defaultlib:std64.lib >& %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console \
+# RUN:   hello64 /defaultlib:std64.lib >& %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64.lib \
+# RUN:   /nodefaultlib:std64.lib >& %t.log || true
+# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
+
+# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64 \
+# RUN:   /nodefaultlib:std64.lib >& %t.log || true
+# RUN: FileCheck -check-prefix=CHECK3 %s < %t.log
+
+CHECK1: hello64.obj: {{[Nn]}}o such file or directory
+CHECK2: hello64: {{[Nn]}}o such file or directory
+CHECK3: hello64.obj: undefined symbol: MessageBoxA
+
+# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64.lib
+
+# RUN: env LIB=%T lld-link /out:%t.exe /entry:main \
+# RUN:   /subsystem:console hello64.obj /defaultlib:std64.lib
diff --git a/test/COFF/noentry.test b/test/COFF/noentry.test
new file mode 100644 (file)
index 0000000..cc02c85
--- /dev/null
@@ -0,0 +1,8 @@
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+# RUN: lld-link /out:%t.dll /dll %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s
+# RUN: lld-link /out:%t.dll /dll /noentry %t.obj
+# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOENTRY %s
+
+ENTRY:   AddressOfEntryPoint: 0x1000
+NOENTRY: AddressOfEntryPoint: 0x0
diff --git a/test/COFF/nopdb.test b/test/COFF/nopdb.test
new file mode 100644 (file)
index 0000000..29797bb
--- /dev/null
@@ -0,0 +1,14 @@
+# Check that /debug creates %t.pdb.
+# RUN: rm -f %t.pdb
+# RUN: lld-link /debug /entry:main /out:%t.exe %p/Inputs/ret42.obj
+# RUN: ls %t.pdb
+
+# Check that /debug /nopdb does not create %t.pdb.
+# RUN: rm -f %t.pdb
+# RUN: lld-link /debug /nopdb /entry:main /out:%t.exe %p/Inputs/ret42.obj
+# RUN: not ls %t.pdb
+
+# Check that /debug /nopdb /pdb:%t.pdb does not create %t.pdb.
+# RUN: rm -f %t.pdb
+# RUN: lld-link /debug /nopdb /pdb:%t.pdb /entry:main /out:%t.exe %p/Inputs/ret42.obj
+# RUN: not ls %t.pdb
diff --git a/test/COFF/opt.test b/test/COFF/opt.test
new file mode 100644 (file)
index 0000000..a8b0e2e
--- /dev/null
@@ -0,0 +1,69 @@
+# RUN: yaml2obj < %s > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj \
+# RUN:   /verbose >& %t.log
+### FileCheck doesn't like empty input, so write something.
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj \
+# RUN:   /verbose /opt:noref >& %t.log
+# RUN: echo dummy >> %t.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log
+
+# CHECK1:     Discarded unused
+# CHECK2-NOT: Discarded unused
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            unused
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/options.test b/test/COFF/options.test
new file mode 100644 (file)
index 0000000..a23da19
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
+BIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
+# RUN: lld-link /allowisolation /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
+ISO-NOT: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
+
+# RUN: lld-link /allowisolation:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOISO %s
+NOISO: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s
+# RUN: lld-link /out:%t.exe /entry:main /highentropyva %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s
+ENT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+
+# RUN: lld-link /out:%t.exe /highentropyva:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOENT %s
+NOENT-NOT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s
+# RUN: lld-link /out:%t.exe /entry:main /nxcompat %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s
+NXCOMPAT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
+
+# RUN: lld-link /out:%t.exe /nxcompat:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NONXCOMPAT %s
+NONXCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s
+# RUN: lld-link /out:%t.exe /entry:main /tsaware %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s
+TSAWARE: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
+
+# RUN: lld-link /tsaware:no /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOTSAWARE %s
+NOTSAWARE-NOT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
diff --git a/test/COFF/order.test b/test/COFF/order.test
new file mode 100644 (file)
index 0000000..bb0a6e5
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: yaml2obj < %p/Inputs/include1a.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/include1b.yaml > %t2.obj
+# RUN: yaml2obj < %p/Inputs/include1c.yaml > %t3.obj
+# RUN: rm -f %t2.lib %t3.lib
+# RUN: llvm-ar cru %t2.lib %t2.obj
+# RUN: llvm-ar cru %t3.lib %t3.obj
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   %t1.obj %t2.lib %t3.obj %t3.lib /verbose >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: order.test.tmp1.obj
+CHECK: order.test.tmp2.lib
+CHECK: order.test.tmp3.obj
+CHECK: order.test.tmp3.lib
+CHECK: order.test.tmp2.lib(order.test.tmp2.obj) for foo
diff --git a/test/COFF/out.test b/test/COFF/out.test
new file mode 100644 (file)
index 0000000..a7b5614
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: mkdir -p %T/out/tmp
+# RUN: cp %t.obj %T/out/out1.obj
+# RUN: cp %t.obj %T/out/tmp/out2
+# RUN: cp %t.obj %T/out/tmp/out3.xyz
+
+# RUN: rm -f out1.exe out2.exe out3.exe out3.dll
+# RUN: lld-link /entry:main %T/out/out1.obj
+# RUN: lld-link /entry:main %T/out/tmp/out2
+# RUN: lld-link /dll /entry:main %T/out/tmp/out3.xyz
+
+# RUN: llvm-readobj out1.exe | FileCheck %s
+# RUN: llvm-readobj out2.exe | FileCheck %s
+# RUN: llvm-readobj out3.dll | FileCheck %s
+
+CHECK: File:
diff --git a/test/COFF/pdb-comdat.test b/test/COFF/pdb-comdat.test
new file mode 100644 (file)
index 0000000..f85dacd
--- /dev/null
@@ -0,0 +1,99 @@
+Consider this example program with an inline function "foo":
+
+==> foo.h <==
+extern int global;
+__inline void foo() {
+  ++global;
+}
+void bar();
+==> pdb_comdat_main.c <==
+#include "foo.h"
+int main(void) {
+  foo();
+  bar();
+  return 42;
+}
+==> pdb_comdat_bar.c <==
+#include "foo.h"
+void bar(void) {
+  foo();
+}
+
+Both object files will contain debug info for foo, but only the debug info from
+pdb_comdat_main.obj should be included in the PDB.
+
+RUN: rm -rf %t && mkdir -p %t && cd %t
+RUN: yaml2obj %S/Inputs/pdb_comdat_main.yaml -o pdb_comdat_main.obj
+RUN: yaml2obj %S/Inputs/pdb_comdat_bar.yaml -o pdb_comdat_bar.obj
+RUN: lld-link pdb_comdat_main.obj pdb_comdat_bar.obj -out:t.exe -debug -pdb:t.pdb -nodefaultlib -entry:main
+RUN: llvm-pdbutil dump -l -symbols t.pdb | FileCheck %s
+
+CHECK:                            Lines
+CHECK: ============================================================
+CHECK-LABEL:   Mod 0000 | `{{.*}}pdb_comdat_main.obj`:
+CHECK:       c:\src\llvm-project\build\pdb_comdat_main.c (MD5: F969E51BBE373436D81492EB61387F36)
+CHECK:       c:\src\llvm-project\build\foo.h (MD5: D74D834EFAC3AE2B45E606A8320B1D5C)
+CHECK-LABEL:   Mod 0001 | `{{.*}}pdb_comdat_bar.obj`:
+CHECK:       c:\src\llvm-project\build\pdb_comdat_bar.c (MD5: 365279DB4FCBEDD721BBFC3B14A953C2)
+CHECK-NOT:       c:\src\llvm-project\build\foo.h
+CHECK-LABEL:   Mod 0002 | `* Linker *`:
+
+CHECK:                           Symbols
+CHECK: ============================================================
+CHECK-LABEL:   Mod 0000 | `{{.*}}pdb_comdat_main.obj`:
+CHECK:     4 | S_OBJNAME [size = 56] sig=0, `C:\src\llvm-project\build\pdb_comdat_main.obj`
+CHECK:    60 | S_COMPILE3 [size = 60]
+CHECK:         machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c
+CHECK:         frontend = 19.0.24215.1, backend = 19.0.24215.1
+CHECK:         flags = security checks | hot patchable
+CHECK:   120 | S_GPROC32_ID [size = 44] `main`
+CHECK:         parent = 0, end = 196, addr = 0002:0000, code size = 24
+CHECK:         debug start = 4, debug end = 19, flags = none
+CHECK:   164 | S_FRAMEPROC [size = 32]
+CHECK:         size = 40, padding size = 0, offset to padding = 0
+CHECK:         bytes of callee saved registers = 0, exception handler addr = 0000:0000
+CHECK:         flags = has async eh | opt speed
+CHECK:   196 | S_END [size = 4]
+CHECK:   200 | S_GDATA32 [size = 24] `global`
+CHECK:         type = 0x0074 (int), addr = 0000:0000
+CHECK:   224 | S_BUILDINFO [size = 8] BuildId = `0x100A`
+CHECK:   232 | S_GPROC32_ID [size = 44] `foo`
+CHECK:         parent = 0, end = 308, addr = 0002:0032, code size = 15
+CHECK:         debug start = 0, debug end = 14, flags = none
+CHECK:   276 | S_FRAMEPROC [size = 32]
+CHECK:         size = 0, padding size = 0, offset to padding = 0
+CHECK:         bytes of callee saved registers = 0, exception handler addr = 0000:0000
+CHECK:         flags = marked inline | has async eh | opt speed
+CHECK:   308 | S_END [size = 4]
+CHECK-LABEL:   Mod 0001 | `{{.*}}pdb_comdat_bar.obj`:
+CHECK:     4 | S_OBJNAME [size = 56] sig=0, `C:\src\llvm-project\build\pdb_comdat_bar.obj`
+CHECK:    60 | S_COMPILE3 [size = 60]
+CHECK:       machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c
+CHECK:       frontend = 19.0.24215.1, backend = 19.0.24215.1
+CHECK:       flags = security checks | hot patchable
+CHECK:   120 | S_GPROC32_ID [size = 44] `bar`
+CHECK:       parent = 0, end = 196, addr = 0002:0048, code size = 14
+CHECK:       debug start = 4, debug end = 9, flags = none
+CHECK:   164 | S_FRAMEPROC [size = 32]
+CHECK:       size = 40, padding size = 0, offset to padding = 0
+CHECK:       bytes of callee saved registers = 0, exception handler addr = 0000:0000
+CHECK:       flags = has async eh | opt speed
+CHECK:   196 | S_END [size = 4]
+CHECK:   200 | S_GDATA32 [size = 24] `global`
+CHECK:       type = 0x0074 (int), addr = 0000:0000
+CHECK:   224 | S_BUILDINFO [size = 8] BuildId = `0x100D`
+CHECK-NOT:   S_GPROC32_ID {{.*}} `foo`
+CHECK-LABEL:   Mod 0002 | `* Linker *`:
+
+Reorder the object files and verify that the other table is selected.
+
+RUN: lld-link pdb_comdat_bar.obj pdb_comdat_main.obj -out:t.exe -debug -pdb:t.pdb -nodefaultlib -entry:main
+RUN: llvm-pdbutil dump -l t.pdb | FileCheck %s --check-prefix=REORDER
+
+REORDER-LABEL:   Mod 0000 | `{{.*}}pdb_comdat_bar.obj`:
+REORDER:       c:\src\llvm-project\build\pdb_comdat_bar.c (MD5: 365279DB4FCBEDD721BBFC3B14A953C2)
+REORDER:       c:\src\llvm-project\build\foo.h (MD5: D74D834EFAC3AE2B45E606A8320B1D5C)
+REORDER-LABEL:   Mod 0001 | `{{.*}}pdb_comdat_main.obj`:
+REORDER:       c:\src\llvm-project\build\pdb_comdat_main.c
+REORDER-NOT:       c:\src\llvm-project\build\foo.h
+REORDER-LABEL:   Mod 0002 | `* Linker *`:
diff --git a/test/COFF/pdb-diff.test b/test/COFF/pdb-diff.test
new file mode 100644 (file)
index 0000000..79b23a5
--- /dev/null
@@ -0,0 +1,212 @@
+This test verifies that we produce PDBs compatible with MSVC in various ways.
+We check in a cl-generated object file, PDB, and original source which serve
+as the "baseline" for us to measure against.  Then we link the same object
+file with LLD and compare the two PDBs.  Since the baseline object file and
+PDB are already checked in, we just run LLD on the object file.
+
+RUN: lld-link /debug /pdb:%T/pdb-diff-lld.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj
+RUN: llvm-pdbutil diff -result -values=false -left-bin-root=%S -right-bin-root=D:/src/llvm-mono/lld/test/COFF/ %T/pdb-diff-lld.pdb %S/Inputs/pdb-diff-cl.pdb | FileCheck %s
+
+CHECK:        ----------------------
+CHECK-NEXT:   |  MSF Super Block   |
+CHECK-NEXT:   |----------------+---|
+CHECK-NEXT:   |           File |   |
+CHECK-NEXT:   |----------------+---|
+CHECK-NEXT:   |     Block Size | I |
+CHECK-NEXT:   |----------------+---|
+CHECK-NEXT:   |    Block Count |
+CHECK-NEXT:   |----------------+---|
+CHECK-NEXT:   |      Unknown 1 | I |
+CHECK-NEXT:   |----------------+---|
+CHECK-NEXT:   | Directory Size |
+CHECK-NEXT:   |----------------+---|
+CHECK-NEXT:   ------------------------------------
+CHECK-NEXT:   |         Stream Directory         |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                         File |   |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                 Stream Count | D |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |            Old MSF Directory | I |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                   PDB Stream | I |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                   TPI Stream | I |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                   DBI Stream | I |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                   IPI Stream | I |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                 New FPO Data | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |          Section Header Data | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |        Named Stream "/names" | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |     Named Stream "/LinkInfo" | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   | Module "Inputs\pdb-diff.obj" | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |          Module "* Linker *" | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                     TPI Hash | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                     IPI Hash | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |           Public Symbol Hash | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |        Public Symbol Records | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |           Global Symbol Hash | D |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   ------------------------------------
+CHECK-NEXT:   |           String Table           |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                         File |   |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |            Number of Strings | D |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                 Hash Version | I |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                    Byte Size |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                    Signature | I |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |                Empty Strings |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |  {{.*}}pdb-diff.cpp | {{[EI]}} |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |  $T0 $ebp = $...p $T0 8 + =  | D |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   |  d:\src\llvm-...er internal) | D |
+CHECK-NEXT:   |------------------------------+---|
+CHECK-NEXT:   ----------------------------
+CHECK-NEXT:   |        PDB Stream        |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |                 File |   |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |          Stream Size |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |                  Age | I |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |                 Guid | D |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |            Signature | D |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |              Version | I |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |       Features (set) | I |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |              Feature | I |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |    Named Stream Size |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |  Named Streams (map) | {{[EI]}} |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |               /names | {{[EI]}} |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   |            /LinkInfo | {{[EI]}} |
+CHECK-NEXT:   |----------------------+---|
+CHECK-NEXT:   ----------------------------------------------
+CHECK-NEXT:   |                 DBI Stream                 |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                                   File |   |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                            Dbi Version | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                                    Age | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                                Machine | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                                  Flags | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                            Build Major | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                            Build Minor | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                           Build Number | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        PDB DLL Version | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                           PDB DLL RBLD | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                              DBG (FPO) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        DBG (Exception) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                            DBG (Fixup) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        DBG (OmapToSrc) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                      DBG (OmapFromSrc) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                       DBG (SectionHdr) | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                      DBG (TokenRidMap) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                            DBG (Xdata) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                            DBG (Pdata) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                           DBG (NewFPO) | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                   DBG (SectionHdrOrig) | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                         Globals Stream | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                         Publics Stream | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                         Symbol Records | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                             Has CTypes | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                Is Incrementally Linked | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                            Is Stripped | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                           Module Count | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                      Source File Count | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   | Module "Inputs\pdb-diff.obj" |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                                 - Modi | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        - Obj File Name | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                         - Debug Stream | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        - C11 Byte Size | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        - C13 Byte Size | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                           - # of files | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                  - Pdb File Path Index | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |               - Source File Name Index | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                     - Symbol Byte Size | D |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |            Module "* Linker *"             |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                                 - Modi | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        - Obj File Name | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                         - Debug Stream | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        - C11 Byte Size | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                        - C13 Byte Size | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                           - # of files | I |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                  - Pdb File Path Index | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |               - Source File Name Index | {{[EI]}} |
+CHECK-NEXT:   |----------------------------------------+---|
+CHECK-NEXT:   |                     - Symbol Byte Size |
+CHECK-NEXT:   |----------------------------------------+---|
+
+
diff --git a/test/COFF/pdb-global-gc.yaml b/test/COFF/pdb-global-gc.yaml
new file mode 100644 (file)
index 0000000..b66b3f2
--- /dev/null
@@ -0,0 +1,116 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: llvm-mc %S/Inputs/pdb-global-gc.s -triple x86_64-windows-msvc -filetype=obj -o %t2.obj
+# RUN: lld-link %t.obj %t2.obj -debug -entry:main \
+# RUN:          -nodefaultlib -debug -out:%t.exe -pdb:%t.pdb -verbose
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# This tests the case where an __imp_ chunk is discarded by linker GC. The debug
+# info may refer to the __imp_ symbol still.
+
+# Compile this code with MSVC to regenerate the test case:
+#   extern char __declspec(dllimport) __wc_mb_cur;
+#   int discarded() { return __wc_mb_cur; }
+#   int main() { return g2; }
+
+# CHECK:                           Symbols
+# CHECK: ============================================================
+# CHECK:   Mod 0000 | `{{.*}}pdb-global-gc.yaml.tmp.obj`:
+# CHECK:     4 | S_GDATA32 [size = 28] `__wc_mb_cur`
+# CHECK-NEXT:       type = 0x0070 (char), addr = 0000:0000
+# CHECK:   Mod 0001 | `{{.*}}pdb-global-gc.yaml.tmp2.obj`:
+# CHECK:   Mod 0002 | `* Linker *`:
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GDATA32
+            DataSym:
+              Type:            112
+              DisplayName:     __wc_mb_cur
+      - !StringTable
+        Strings:
+    Relocations:
+      - VirtualAddress:  20
+        SymbolName:      __wc_mb_cur
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  24
+        SymbolName:      __wc_mb_cur
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     0FBE0500000000C3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      __wc_mb_cur
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          240
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          11
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        2906070869
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        2139436471
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            discarded
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __wc_mb_cur
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-import-gc.yaml b/test/COFF/pdb-import-gc.yaml
new file mode 100644 (file)
index 0000000..80484cb
--- /dev/null
@@ -0,0 +1,114 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link %t.obj %S/Inputs/pdb-import-gc.lib -debug -entry:main \
+# RUN:          -nodefaultlib -debug -out:%t.exe -pdb:%t.pdb
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# This tests the case where an __imp_ chunk is discarded by linker GC. The debug
+# info may refer to the __imp_ symbol still.
+
+# Compile this code with MSVC to regenerate the test case:
+#   extern char __declspec(dllimport) __wc_mb_cur;
+#   int discarded() { return __wc_mb_cur; }
+#   int main() { return g2; }
+
+# CHECK:                           Symbols
+# CHECK: ============================================================
+# CHECK:   Mod 0000 | `{{.*}}pdb-import-gc.yaml.tmp.obj`:
+# CHECK:     4 | S_GDATA32 [size = 32] `__imp___wc_mb_cur`
+# CHECK-NEXT:       type = 0x0070 (char), addr = 0000:0000
+# CHECK:   Mod 0001 | `* Linker *`:
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GDATA32
+            DataSym:
+              Type:            112
+              DisplayName:     __imp___wc_mb_cur
+      - !StringTable
+        Strings:
+    Relocations:
+      - VirtualAddress:  20
+        SymbolName:      __imp___wc_mb_cur
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  24
+        SymbolName:      __imp___wc_mb_cur
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     488B05000000000FBE00C3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      __imp___wc_mb_cur
+        Type:            IMAGE_REL_AMD64_REL32
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          240
+      NumberOfRelocations: 2
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          11
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        2906070869
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        2139436471
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_NODUPLICATES
+  - Name:            discarded
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __imp___wc_mb_cur
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-invalid-func-type.yaml b/test/COFF/pdb-invalid-func-type.yaml
new file mode 100644 (file)
index 0000000..686079e
--- /dev/null
@@ -0,0 +1,146 @@
+# This test has an S_GPROC32_ID symbol with an invalid type index. Make sure we
+# keep the record, or we'll have unbalanced scopes, which is bad. This situation
+# can arise when we can't find the type server PDB.
+
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# CHECK: Mod 0000 | `{{.*}}pdb-invalid-func-type.yaml.tmp.obj`:
+# CHECK:      4 | S_GPROC32_ID [size = 44] `main`
+# CHECK:          parent = 0, end = 80, addr = 0001:0000, code size = 3
+# CHECK:     48 | S_FRAMEPROC [size = 32]
+# CHECK:     80 | S_END [size = 4]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              CodeSize:        3
+              DbgStart:        0
+              DbgEnd:          2
+              # Corrupt function type!
+              FunctionType:    4101
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        3
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'c:\src\llvm-project\build\t.c'
+            Lines:
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !FileChecksums
+        Checksums:
+          - FileName:        'c:\src\llvm-project\build\t.c'
+            Kind:            MD5
+            Checksum:        270A878DCC1B845655B162F56C4F5020
+      - !StringTable
+        Strings:
+          - 'c:\src\llvm-project\build\t.c'
+    Relocations:
+      - VirtualAddress:  44
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  48
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  100
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  104
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            main
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     33C0C3
+symbols:
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          328
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          564
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          3
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        4021952397
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-lib.s b/test/COFF/pdb-lib.s
new file mode 100644 (file)
index 0000000..74d987e
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && mkdir -p %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o foo.obj
+# RUN: llc %S/Inputs/bar.ll -filetype=obj -mtriple=i686-windows-msvc -o bar.obj
+# RUN: llvm-lib bar.obj -out:bar.lib
+# RUN: lld-link -debug -pdb:foo.pdb foo.obj bar.lib -out:foo.exe -entry:main
+# RUN: llvm-pdbutil dump -modules %t/foo.pdb | FileCheck %s
+
+# Make sure that the PDB has module descriptors. foo.obj and bar.lib should be
+# absolute paths, and bar.obj should be the relative path passed to llvm-lib.
+
+# CHECK:                               Modules
+# CHECK-NEXT: ============================================================
+# CHECK-NEXT:   Mod 0000 | Name: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`:
+# CHECK-NEXT:              Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`:
+# CHECK-NEXT:              debug stream: 9, # files: 0, has ec info: false
+# CHECK-NEXT:              pdb file ni: 0 ``, src file ni: 0 ``
+# CHECK-NEXT:   Mod 0001 | Name: `bar.obj`:
+# CHECK-NEXT:              Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`:
+# CHECK-NEXT:              debug stream: 10, # files: 0, has ec info: false
+# CHECK-NEXT:              pdb file ni: 0 ``, src file ni: 0 ``
+# CHECK-NEXT:   Mod 0002 | Name: `* Linker *`:
+# CHECK-NEXT:              Obj: ``:
+# CHECK-NEXT:              debug stream: 11, # files: 0, has ec info: false
+# CHECK-NEXT:              pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 ``
+
+        .def     _main;
+        .scl    2;
+        .type   32;
+        .endef
+        .globl  _main
+_main:
+        calll _bar
+        xor %eax, %eax
+        retl
+
diff --git a/test/COFF/pdb-linker-module.test b/test/COFF/pdb-linker-module.test
new file mode 100644 (file)
index 0000000..ce366b6
--- /dev/null
@@ -0,0 +1,18 @@
+RUN: lld-link /debug /pdb:%t.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj
+RUN: llvm-pdbutil dump -modules -symbols %t.pdb | FileCheck %s
+
+CHECK:      Mod 0001 | `* Linker *`:
+CHECK-NEXT:  4 | S_OBJNAME [size = 20] sig=0, `* Linker *`
+CHECK-NEXT: 24 | S_COMPILE3 [size = 40]
+CHECK-NEXT:      machine = intel 80386, Ver = LLVM Linker, language = link
+CHECK-NEXT:      frontend = 0.0.0.0, backend = 0.0.0.0
+CHECK-NEXT:      flags = none
+CHECK-NEXT: 64 | S_ENVBLOCK
+CHECK-NEXT: - cwd
+CHECK-NEXT: -
+CHECK-NEXT: - exe
+CHECK-NEXT: - {{.*}}lld-link
+CHECK-NEXT: - pdb
+CHECK-NEXT: - {{.*}}pdb-linker-module{{.*}}pdb
+CHECK-NEXT: - cmd
+CHECK-NEXT: - /debug /pdb:{{.*}}pdb-linker-module{{.*}}pdb /nodefaultlib /entry:main {{.*}}pdb-diff.obj
diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test
new file mode 100644 (file)
index 0000000..c1becba
--- /dev/null
@@ -0,0 +1,14 @@
+# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
+# RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
+# RUN:   %t1.obj %t2.obj
+
+# RUN: llvm-pdbutil pdb2yaml -pdb-stream %t.pdb | FileCheck %s
+
+# CHECK:      PdbStream:
+# CHECK-NEXT:   Age:             0
+# CHECK-NEXT:   Guid:
+# CHECK-NEXT:   Signature:
+# CHECK-NEXT:   Features:        [ VC140 ]
+# CHECK-NEXT:   Version:         VC70
+
diff --git a/test/COFF/pdb-options.test b/test/COFF/pdb-options.test
new file mode 100644 (file)
index 0000000..1468c4f
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
+
+; If /DEBUG is not specified, /pdb is ignored.
+# RUN: rm -f %t.pdb
+# RUN: lld-link /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj
+# RUN: not ls %t.pdb
+
+; If /DEBUG and /pdb are specified, it uses the specified name.
+# RUN: lld-link /DEBUG /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj
+# RUN: ls %t.pdb
+# RUN: rm %t.pdb
+
+; If /DEBUG is specified but not /pdb, it uses a default name in the current
+; directory.  This is a bit hacky since but we need to be IN our test specific
+; temporary directory when we run this command or we can't test this
+# RUN: cd %T
+# RUN: lld-link /DEBUG /entry:main /nodefaultlib %t1.obj %t2.obj
+# RUN: ls %t1.pdb
+# RUN: rm %t*
+# RUN: cd %T/..\r
diff --git a/test/COFF/pdb-safeseh.yaml b/test/COFF/pdb-safeseh.yaml
new file mode 100644 (file)
index 0000000..24215bd
--- /dev/null
@@ -0,0 +1,85 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link -debug -entry:main -out:%t.exe -pdb:%t.pdb %t.obj
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# There is an S_GDATA32 symbol record with .secrel32 and .secidx relocations in
+# it in this debug info. This is similar to the relocations in the loadcfg.obj
+# file in the MSVC CRT. We need to make sure that our relocation logic matches
+# MSVC's for these absolute, linker-provided symbols.
+
+# CHECK: Mod 0000 |
+# CHECK-NEXT: 4 | S_GDATA32 [size = 40] `___safe_se_handler_table`
+# CHECK-NEXT:     type = 0x0022 (unsigned long), addr = 0003:0000
+# CHECK-NEXT: Mod 0001 | `* Linker *`:
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GDATA32
+            DataSym:
+              Type:            34
+              DisplayName:     ___safe_se_handler_table
+      - !StringTable
+        Strings:
+    Relocations:
+      - VirtualAddress:  20
+        SymbolName:      ___safe_se_handler_table
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  24
+        SymbolName:      ___safe_se_handler_table
+        Type:            IMAGE_REL_I386_SECTION
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     488D0500000000C3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      ___safe_se_handler_table
+        Type:            IMAGE_REL_I386_REL32
+symbols:
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          372
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1092178131
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            ___safe_se_handler_table
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
+
diff --git a/test/COFF/pdb-scopes.test b/test/COFF/pdb-scopes.test
new file mode 100644 (file)
index 0000000..7beb597
--- /dev/null
@@ -0,0 +1,75 @@
+Consider this program:
+
+$ cat a.c
+void g(int x) {}
+void f(int x);
+int main(int argc) {
+  if (argc) {
+    int x = 42;
+    f(x);
+  } else {
+    int y = 13;
+    f(y);
+  }
+}
+
+$ cat b.c
+extern void g();
+void f(int x) {
+  if (x) {
+    int y = x + 3;
+    g(y);
+  } else {
+    int w = x + 4;
+    g(w);
+  }
+}
+
+This program is interesting because there are two TUs, and each TU has nested
+scopes. Make sure we get the right parent and end offsets.
+
+RUN: yaml2obj %S/Inputs/pdb-scopes-a.yaml -o %t-a.obj
+RUN: yaml2obj %S/Inputs/pdb-scopes-b.yaml -o %t-b.obj
+RUN: lld-link %t-a.obj %t-b.obj -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb
+RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`:
+CHECK: 104 | S_GPROC32_ID [size = 44] `g`
+CHECK:       parent = 0, end = 196, addr = 0002:0000, code size = 5
+CHECK:       debug start = 4, debug end = 4, flags = none
+CHECK: 180 | S_REGREL32 [size = 16] `x`
+CHECK: 196 | S_END [size = 4]
+CHECK: 200 | S_GPROC32_ID [size = 44] `main`
+CHECK:       parent = 0, end = 384, addr = 0002:0016, code size = 58
+CHECK:       debug start = 8, debug end = 53, flags = none
+CHECK: 276 | S_REGREL32 [size = 20] `argc`
+CHECK: 296 | S_BLOCK32 [size = 24] ``
+CHECK:       parent = 200, end = 336
+CHECK:       code size = 17, addr = 0002:0031
+CHECK: 320 | S_REGREL32 [size = 16] `x`
+CHECK: 336 | S_END [size = 4]
+CHECK: 340 | S_BLOCK32 [size = 24] ``
+CHECK:       parent = 200, end = 380
+CHECK:       code size = 17, addr = 0002:0050
+CHECK: 364 | S_REGREL32 [size = 16] `y`
+CHECK: 380 | S_END [size = 4]
+CHECK: 384 | S_END [size = 4]
+
+CHECK-LABEL: Mod 0001 | `{{.*}}pdb-scopes.test.tmp-b.obj`:
+CHECK: 104 | S_GPROC32_ID [size = 44] `f`
+CHECK:       parent = 0, end = 284, addr = 0002:0080, code size = 62
+CHECK:       debug start = 8, debug end = 57, flags = none
+CHECK: 180 | S_REGREL32 [size = 16] `x`
+CHECK: 196 | S_BLOCK32 [size = 24] ``
+CHECK:       parent = 104, end = 236
+CHECK:       code size = 20, addr = 0002:0095
+CHECK: 220 | S_REGREL32 [size = 16] `y`
+CHECK: 236 | S_END [size = 4]
+CHECK: 240 | S_BLOCK32 [size = 24] ``
+CHECK:       parent = 104, end = 280
+CHECK:       code size = 20, addr = 0002:0117
+CHECK: 264 | S_REGREL32 [size = 16] `w`
+CHECK: 280 | S_END [size = 4]
+CHECK: 284 | S_END [size = 4]
+
+CHECK-LABEL: Mod 0002 | `* Linker *`:
diff --git a/test/COFF/pdb-secrel-absolute.yaml b/test/COFF/pdb-secrel-absolute.yaml
new file mode 100644 (file)
index 0000000..c514e54
--- /dev/null
@@ -0,0 +1,84 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link -debug -entry:main -out:%t.exe -pdb:%t.pdb %t.obj
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# There is an S_GDATA32 symbol record with .secrel32 and .secidx relocations in
+# it in this debug info. This is similar to the relocations in the loadcfg.obj
+# file in the MSVC CRT. We need to make sure that our relocation logic matches
+# MSVC's for these absolute, linker-provided symbols.
+
+# CHECK: Mod 0000 |
+# CHECK-NEXT:  4 | S_GDATA32 [size = 36] `__guard_fids_table`
+# CHECK-NEXT:     type = 0x0022 (unsigned long), addr = 0003:0000
+# CHECK-NEXT: Mod 0001 | `* Linker *`:
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GDATA32
+            DataSym:
+              Type:            34
+              DisplayName:     __guard_fids_table
+      - !StringTable
+        Strings:
+    Relocations:
+      - VirtualAddress:  20
+        SymbolName:      __guard_fids_table
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  24
+        SymbolName:      __guard_fids_table
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     488D0500000000C3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      __guard_fids_table
+        Type:            IMAGE_REL_AMD64_REL32
+symbols:
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          372
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        1092178131
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __guard_fids_table
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-source-lines.test b/test/COFF/pdb-source-lines.test
new file mode 100644 (file)
index 0000000..f9e0e5c
--- /dev/null
@@ -0,0 +1,124 @@
+Test the linker line tables on roughly the following example:
+
+==> foo.h <==
+void bar(void);
+inline void foo(void) {
+  bar();
+}
+==> pdb_lines_1.c <==
+#include "foo.h"
+int main(void) {
+  foo();
+  return 42;
+}
+==> pdb_lines_2.c <==
+void bar(void) {
+}
+
+$ cl -c -Z7 pdb_lines*.c
+
+RUN: yaml2obj %S/Inputs/pdb_lines_1.yaml -o %t.pdb_lines_1.obj
+RUN: yaml2obj %S/Inputs/pdb_lines_2.yaml -o %t.pdb_lines_2.obj
+RUN: lld-link -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb %t.pdb_lines_1.obj %t.pdb_lines_2.obj
+RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | FileCheck %s
+
+CHECK-LABEL: DbiStream:       
+CHECK-NEXT:   VerHeader:       V70
+CHECK-NEXT:   Age:             1
+CHECK-NEXT:   BuildNumber:     0
+CHECK-NEXT:   PdbDllVersion:   0
+CHECK-NEXT:   PdbDllRbld:      0
+CHECK-NEXT:   Flags:           0
+CHECK-NEXT:   MachineType:     x86
+CHECK-NEXT:   Modules:         
+
+CHECK-LABEL:    - Module:          {{.*}}pdb_lines_1.obj
+CHECK-NEXT:       ObjFile:         {{.*}}pdb_lines_1.obj
+CHECK-NEXT:       SourceFiles:     
+CHECK-NEXT:         - '{{.*}}pdb_lines_1.c'
+CHECK-NEXT:         - '{{.*}}foo.h'
+CHECK-NEXT:       Subsections:     
+CHECK-NEXT:         - !Lines
+CHECK-NEXT:           CodeSize:        19
+CHECK-NEXT:           Flags:           [  ]
+CHECK-NEXT:           RelocOffset:     0
+CHECK-NEXT:           RelocSegment:    2
+CHECK-NEXT:           Blocks:          
+CHECK-NEXT:             - FileName:        '{{.*}}pdb_lines_1.c'
+CHECK-NEXT:               Lines:           
+CHECK-NEXT:                 - Offset:          0
+CHECK-NEXT:                   LineStart:       2
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:                 - Offset:          4
+CHECK-NEXT:                   LineStart:       3
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:                 - Offset:          9
+CHECK-NEXT:                   LineStart:       4
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:                 - Offset:          14
+CHECK-NEXT:                   LineStart:       5
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:               Columns:         
+CHECK-NEXT:         - !FileChecksums
+CHECK-NEXT:           Checksums:       
+CHECK-NEXT:             - FileName:        '{{.*}}pdb_lines_1.c'
+CHECK-NEXT:               Kind:            MD5
+CHECK-NEXT:               Checksum:        4EB19DCD86C3BA2238A255C718572E7B
+CHECK-NEXT:             - FileName:        '{{.*}}foo.h'
+CHECK-NEXT:               Kind:            MD5
+CHECK-NEXT:               Checksum:        061EB73ABB642532857A4F1D9CBAC323
+CHECK-NEXT:         - !Lines
+CHECK-NEXT:           CodeSize:        14
+CHECK-NEXT:           Flags:           [  ]
+CHECK-NEXT:           RelocOffset:     32
+CHECK-NEXT:           RelocSegment:    2
+CHECK-NEXT:           Blocks:          
+CHECK-NEXT:             - FileName:        '{{.*}}foo.h'
+CHECK-NEXT:               Lines:           
+CHECK-NEXT:                 - Offset:          0
+CHECK-NEXT:                   LineStart:       2
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:                 - Offset:          4
+CHECK-NEXT:                   LineStart:       3
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:                 - Offset:          9
+CHECK-NEXT:                   LineStart:       4
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:               Columns:         
+
+CHECK-LABEL:    - Module:          {{.*}}pdb_lines_2.obj
+CHECK-NEXT:       ObjFile:         {{.*}}pdb_lines_2.obj
+CHECK-NEXT:       SourceFiles:     
+CHECK-NEXT:         - '{{.*}}pdb_lines_2.c'
+CHECK-NEXT:       Subsections:     
+CHECK-NEXT:         - !Lines
+CHECK-NEXT:           CodeSize:        1
+CHECK-NEXT:           Flags:           [  ]
+CHECK-NEXT:           RelocOffset:     48
+CHECK-NEXT:           RelocSegment:    2
+CHECK-NEXT:           Blocks:          
+CHECK-NEXT:             - FileName:        '{{.*}}pdb_lines_2.c'
+CHECK-NEXT:               Lines:           
+CHECK-NEXT:                 - Offset:          0
+CHECK-NEXT:                   LineStart:       1
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:                 - Offset:          0
+CHECK-NEXT:                   LineStart:       2
+CHECK-NEXT:                   IsStatement:     true
+CHECK-NEXT:                   EndDelta:        0
+CHECK-NEXT:               Columns:         
+CHECK-NEXT:         - !FileChecksums
+CHECK-NEXT:           Checksums:       
+CHECK-NEXT:             - FileName:        '{{.*}}pdb_lines_2.c'
+CHECK-NEXT:               Kind:            MD5
+CHECK-NEXT:               Checksum:        DF91CB3A2B8D917486574BB50CAC4CC7
+CHECK-NEXT:     - Module:          '* Linker *'
+CHECK-NEXT:       ObjFile:         ''
diff --git a/test/COFF/pdb-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml
new file mode 100644 (file)
index 0000000..2ad6f5b
--- /dev/null
@@ -0,0 +1,344 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link %t.obj -nodefaultlib -entry:main -debug -out:%t.exe -pdb:%t.pdb
+# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
+
+# To regenerate the object file:
+# $ cat symbol-types.c
+# struct Foo { int x; };
+# typedef struct Foo UDT_Foo;
+# UDT_Foo global_foo = {42};
+# int main() { return global_foo.x; }
+# $ cl -c -Z7 symbol-types.c
+
+# Note that the type of 'global' goes from 0x1005 in the object file to 0x1004
+# in the PDB because the LF_FUNC_ID is moved to the id stream.
+
+# CHECK:                           Symbols
+# CHECK: ============================================================
+# CHECK-LABEL:   Mod 0000 | `{{.*}}pdb-symbol-types.yaml.tmp.obj`:
+# CHECK:     4 | S_OBJNAME [size = 52] sig=0, `C:\src\llvm-project\build\symbol-types.obj`
+# CHECK:    56 | S_COMPILE3 [size = 60]
+# CHECK:         machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c
+# CHECK:         frontend = 19.0.24215.1, backend = 19.0.24215.1
+# CHECK:         flags = security checks | hot patchable
+# CHECK:   116 | S_GPROC32_ID [size = 44] `main`
+# CHECK:         parent = 0, end = 192, addr = 0002:0000, code size = 7
+# CHECK:         debug start = 0, debug end = 6, flags = none
+# CHECK:   160 | S_FRAMEPROC [size = 32]
+# CHECK:         size = 0, padding size = 0, offset to padding = 0
+# CHECK:         bytes of callee saved registers = 0, exception handler addr = 0000:0000
+# CHECK:         flags = has async eh | opt speed
+# CHECK:   192 | S_END [size = 4]
+# CHECK:   196 | S_GDATA32 [size = 28] `global_foo`
+# CHECK:         type = 0x1004 (Foo), addr = 0001:0000
+# CHECK:   224 | S_UDT [size = 16] `UDT_Foo`
+# CHECK:         original type = 0x1004
+# CHECK:   240 | S_UDT [size = 12] `Foo`
+# CHECK:         original type = 0x1004
+# CHECK:   252 | S_BUILDINFO [size = 8] BuildId = `0x100A`
+# CHECK-LABEL:   Mod 0001 | `* Linker *`:
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .drectve
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'C:\src\llvm-project\build\symbol-types.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ SecurityChecks, HotPatch ]
+              Machine:         X64
+              FrontendMajor:   19
+              FrontendMinor:   0
+              FrontendBuild:   24215
+              FrontendQFE:     1
+              BackendMajor:    19
+              BackendMinor:    0
+              BackendBuild:    24215
+              BackendQFE:      1
+              Version:         'Microsoft (R) Optimizing Compiler'
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              CodeSize:        7
+              DbgStart:        0
+              DbgEnd:          6
+              FunctionType:    4098
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        7
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'c:\src\llvm-project\build\symbol-types.c'
+            Lines:
+              - Offset:          0
+                LineStart:       4
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          0
+                LineStart:       5
+                IsStatement:     true
+                EndDelta:        0
+              - Offset:          6
+                LineStart:       6
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !Symbols
+        Records:
+          - Kind:            S_GDATA32
+            DataSym:
+              Type:            4101
+              DisplayName:     global_foo
+          - Kind:            S_UDT
+            UDTSym:
+              Type:            4101
+              UDTName:         UDT_Foo
+          - Kind:            S_UDT
+            UDTSym:
+              Type:            4101
+              UDTName:         Foo
+      - !FileChecksums
+        Checksums:
+          - FileName:        'c:\src\llvm-project\build\symbol-types.c'
+            Kind:            MD5
+            Checksum:        F833E1A4909FF6FEC5689A664F3BE725
+      - !StringTable
+        Strings:
+          - 'c:\src\llvm-project\build\symbol-types.c'
+      - !Symbols
+        Records:
+          - Kind:            S_BUILDINFO
+            BuildInfoSym:
+              BuildId:         4111
+    Relocations:
+      - VirtualAddress:  164
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  168
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  220
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  224
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  284
+        SymbolName:      global_foo
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  288
+        SymbolName:      global_foo
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:
+      - Kind:            LF_ARGLIST
+        ArgList:
+          ArgIndices:      [ 0 ]
+      - Kind:            LF_PROCEDURE
+        Procedure:
+          ReturnType:      116
+          CallConv:        NearC
+          Options:         [ None ]
+          ParameterCount:  0
+          ArgumentList:    4096
+      - Kind:            LF_FUNC_ID
+        FuncId:
+          ParentScope:     0
+          FunctionType:    4097
+          Name:            main
+      - Kind:            LF_STRUCTURE
+        Class:
+          MemberCount:     0
+          Options:         [ None, ForwardReference, HasUniqueName ]
+          FieldList:       0
+          Name:            Foo
+          UniqueName:      '.?AUFoo@@'
+          DerivationList:  0
+          VTableShape:     0
+          Size:            0
+      - Kind:            LF_FIELDLIST
+        FieldList:
+          - Kind:            LF_MEMBER
+            DataMember:
+              Attrs:           3
+              Type:            116
+              FieldOffset:     0
+              Name:            x
+      - Kind:            LF_STRUCTURE
+        Class:
+          MemberCount:     1
+          Options:         [ None, HasUniqueName ]
+          FieldList:       4100
+          Name:            Foo
+          UniqueName:      '.?AUFoo@@'
+          DerivationList:  0
+          VTableShape:     0
+          Size:            4
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'c:\src\llvm-project\build\symbol-types.c'
+      - Kind:            LF_UDT_SRC_LINE
+        UdtSourceLine:
+          UDT:             4101
+          SourceFile:      4102
+          LineNumber:      1
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'C:\src\llvm-project\build'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
+      - Kind:            LF_SUBSTR_LIST
+        StringList:
+          StringIndices:   [ 4106 ]
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              4107
+          String:          ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          symbol-types.c
+      - Kind:            LF_STRING_ID
+        StringId:
+          Id:              0
+          String:          'C:\src\llvm-project\build\vc140.pdb'
+      - Kind:            LF_BUILDINFO
+        BuildInfo:
+          ArgIndices:      [ 4104, 4105, 4109, 4110, 4108 ]
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     2A000000
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     8B0500000000C3
+    Relocations:
+      - VirtualAddress:  2
+        SymbolName:      global_foo
+        Type:            IMAGE_REL_AMD64_REL32
+symbols:
+  - Name:            '@comp.id'
+    Value:           17063575
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           2147484048
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          432
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          732
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        3482275674
+      Number:          0
+  - Name:            global_foo
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          7
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        3635526833
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-type-server-missing.yaml b/test/COFF/pdb-type-server-missing.yaml
new file mode 100644 (file)
index 0000000..91bb04f
--- /dev/null
@@ -0,0 +1,132 @@
+# This is an object compiled with /Zi (see the LF_TYPESERVER2 record) without an
+# adjacent type server PDB. Test that LLD fails gracefully on it.
+
+# FIXME: Ideally we'd do what MSVC does, which is to warn and drop all debug
+# info in the object with the missing PDB.
+
+# RUN: yaml2obj %s -o %t.obj
+# RUN: not lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
+
+# CHECK: error: Type server PDB was not found
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              CodeSize:        3
+              DbgStart:        0
+              DbgEnd:          2
+              FunctionType:    4199
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 0
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        3
+        Flags:           [  ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        'c:\src\llvm-project\build\t.c'
+            Lines:
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     true
+                EndDelta:        0
+            Columns:
+      - !FileChecksums
+        Checksums:
+          - FileName:        'c:\src\llvm-project\build\t.c'
+            Kind:            MD5
+            Checksum:        270A878DCC1B845655B162F56C4F5020
+      - !StringTable
+        Strings:
+          - 'c:\src\llvm-project\build\t.c'
+    Relocations:
+      - VirtualAddress:  44
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  48
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  100
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECREL
+      - VirtualAddress:  104
+        SymbolName:      main
+        Type:            IMAGE_REL_AMD64_SECTION
+  - Name:            '.debug$T'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Types:
+      - Kind:            LF_TYPESERVER2
+        TypeServer2:
+          Guid:            '{01DF191B-22BF-6B42-96CE-5258B8329FE5}'
+          Age:             18
+          Name:            'C:\src\llvm-project\build\definitely_not_found_for_sure.pdb'
+  - Name:            '.text$mn'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     33C0C3
+symbols:
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          328
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$T'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          564
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          3
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        4021952397
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-type-server-simple.test b/test/COFF/pdb-type-server-simple.test
new file mode 100644 (file)
index 0000000..c0de4e3
--- /dev/null
@@ -0,0 +1,91 @@
+Replicate this scenario:
+
+$ cat a.c
+struct Foo { int x; };
+int g(struct Foo *p);
+int main() {
+  struct Foo f = {42};
+  return g(&f);
+}
+
+$ cat b.c
+struct Foo { int x; };
+int g(struct Foo *p) { return p->x; }
+
+$ cl -c a.c b.c -Zi -Fdts.pdb
+
+$ lld-link a.obj b.obj -debug -entry:main -nodefaultlib -out:t.exe
+
+RUN: rm -rf %t && mkdir -p %t && cd %t
+RUN: yaml2obj %S/Inputs/pdb-type-server-simple-a.yaml -o a.obj
+RUN: yaml2obj %S/Inputs/pdb-type-server-simple-b.yaml -o b.obj
+RUN: llvm-pdbutil yaml2pdb %S/Inputs/pdb-type-server-simple-ts.yaml -pdb ts.pdb
+RUN: lld-link a.obj b.obj -entry:main -debug -out:t.exe -pdb:t.pdb -nodefaultlib
+RUN: llvm-pdbutil dump -symbols -types -ids %t/t.pdb | FileCheck %s
+
+
+CHECK-LABEL: Types (TPI Stream)
+CHECK: ============================================================
+
+CHECK:   [[FOO_DECL:[^ ]*]] | LF_STRUCTURE [size = 36] `Foo`
+
+CHECK:   [[FOO_PTR:[^ ]*]] | LF_POINTER [size = 12]
+CHECK-NEXT:            referent = [[FOO_DECL]]
+
+CHECK:   [[G_ARGS:[^ ]*]] | LF_ARGLIST [size = 12]
+CHECK-NEXT:            [[FOO_PTR]]: `Foo*`
+
+CHECK:   [[G_PROTO:[^ ]*]] | LF_PROCEDURE [size = 16]
+CHECK-NEXT:       return type = 0x0074 (int), # args = 1, param list = [[G_ARGS]]
+CHECK-NEXT:       calling conv = cdecl, options = None
+
+CHECK:   [[FOO_COMPLETE:[^ ]*]] | LF_STRUCTURE [size = 36] `Foo`
+CHECK-NEXT:       unique name: `.?AUFoo@@`
+CHECK-NEXT:       vtable: <no type>, base list: <no type>, field list: 0x{{.*}}
+CHECK:            options: has unique name
+CHECK:   [[MAIN_PROTO:[^ ]*]] | LF_PROCEDURE [size = 16]
+CHECK:            return type = 0x0074 (int), # args = 0, param list = 0x{{.*}}
+CHECK:            calling conv = cdecl, options = None
+
+
+CHECK-LABEL:                      Types (IPI Stream)
+CHECK: ============================================================
+CHECK:   [[MAIN_ID:[^ ]*]] | LF_FUNC_ID [size = 20]
+CHECK:            name = main, type = [[MAIN_PROTO]], parent scope = <no type>
+CHECK:   [[G_ID:[^ ]*]] | LF_FUNC_ID [size = 16]
+CHECK:            name = g, type = [[G_PROTO]], parent scope = <no type>
+CHECK:   [[A_BUILD:[^ ]*]] | LF_BUILDINFO [size = 28]
+CHECK:            {{.*}}: `a.c`
+CHECK:   [[B_BUILD:[^ ]*]] | LF_BUILDINFO [size = 28]
+CHECK:            {{.*}}: `b.c`
+
+CHECK-LABEL:                           Symbols
+CHECK: ============================================================
+CHECK-LABEL:   Mod 0000 | `{{.*}}a.obj`:
+CHECK:        4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\a.obj`
+CHECK:      104 | S_GPROC32_ID [size = 44] `main`
+CHECK:            parent = 0, end = 196, addr = 0002:0000, code size = 27
+CHECK:            type = {{.*}}, debug start = 4, debug end = 22, flags = none
+CHECK:      200 | S_UDT [size = 12] `Foo`
+CHECK:            original type = [[FOO_COMPLETE]]
+CHECK:      212 | S_BUILDINFO [size = 8] BuildId = `[[A_BUILD]]`
+CHECK-LABEL:   Mod 0001 | `{{.*}}b.obj`:
+CHECK:        4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\b.obj`
+CHECK:       44 | S_COMPILE3 [size = 60]
+CHECK:            machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c
+CHECK:            frontend = 19.0.24215.1, backend = 19.0.24215.1
+CHECK:            flags = security checks | hot patchable
+CHECK:      104 | S_GPROC32_ID [size = 44] `g`
+CHECK:            parent = 0, end = 196, addr = 0002:0032, code size = 13
+CHECK:            type = {{.*}}, debug start = 5, debug end = 12, flags = none
+CHECK:      148 | S_FRAMEPROC [size = 32]
+CHECK:            size = 0, padding size = 0, offset to padding = 0
+CHECK:            bytes of callee saved registers = 0, exception handler addr = 0000:0000
+CHECK:            flags = has async eh | opt speed
+CHECK:      180 | S_REGREL32 [size = 16] `p`
+CHECK:            type = [[FOO_PTR]] (Foo*), register = rsp, offset = 8
+CHECK:      196 | S_END [size = 4]
+CHECK:      200 | S_UDT [size = 12] `Foo`
+CHECK:            original type = [[FOO_COMPLETE]]
+CHECK:      212 | S_BUILDINFO [size = 8] BuildId = `[[B_BUILD]]`
+CHECK-LABEL:   Mod 0002 | `* Linker *`:
diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test
new file mode 100644 (file)
index 0000000..a4cd4f7
--- /dev/null
@@ -0,0 +1,202 @@
+# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
+# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
+# RUN:   %t1.obj %t2.obj
+
+# RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \
+# RUN:   -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s
+
+# RUN: llvm-pdbutil dump -modules -section-map -section-contribs \
+# RUN:   -types -ids %t.pdb | FileCheck -check-prefix RAW %s
+
+# CHECK:      MSF:
+# CHECK-NEXT:   SuperBlock:
+# CHECK-NEXT:     BlockSize:       4096
+# CHECK-NEXT:     FreeBlockMap:    1
+# CHECK-NEXT:     NumBlocks:
+# CHECK-NEXT:     NumDirectoryBytes:
+# CHECK-NEXT:     Unknown1:        0
+# CHECK-NEXT:     BlockMapAddr:
+# CHECK-NEXT:   NumDirectoryBlocks:
+# CHECK-NEXT:   DirectoryBlocks:
+# CHECK-NEXT:   NumStreams:
+# CHECK-NEXT:   FileSize:
+# CHECK-NEXT: StreamSizes:
+# CHECK:      StreamMap:
+# CHECK:      PdbStream:
+# CHECK-NEXT:   Age:             1
+# CHECK-NEXT:   Guid:
+# CHECK-NEXT:   Signature:
+# CHECK-NEXT:   Features:        [ VC140 ]
+# CHECK-NEXT:   Version:         VC70
+# CHECK-NEXT: DbiStream:
+# CHECK-NEXT:   VerHeader:       V70
+# CHECK-NEXT:   Age:             1
+# CHECK-NEXT:   BuildNumber:     0
+# CHECK-NEXT:   PdbDllVersion:   0
+# CHECK-NEXT:   PdbDllRbld:      0
+# CHECK-NEXT:   Flags:           0
+# CHECK-NEXT:   MachineType:     x86
+# CHECK-NEXT: TpiStream:
+# CHECK-NEXT:   Version:         VC80
+# CHECK-NEXT:   Records:
+# CHECK-NEXT:     - Kind:            LF_ARGLIST
+# CHECK-NEXT:       ArgList:
+# CHECK-NEXT:         ArgIndices:      [  ]
+# CHECK-NEXT:     - Kind:            LF_PROCEDURE
+# CHECK-NEXT:       Procedure:
+# CHECK-NEXT:         ReturnType:      116
+# CHECK-NEXT:         CallConv:        NearC
+# CHECK-NEXT:         Options:         [ None ]
+# CHECK-NEXT:         ParameterCount:  0
+# CHECK-NEXT:         ArgumentList:    4096
+# CHECK-NEXT:     - Kind:            LF_POINTER
+# CHECK-NEXT:       Pointer:
+# CHECK-NEXT:         ReferentType:    4097
+# CHECK-NEXT:         Attrs:           65548
+# CHECK-NEXT:     - Kind:            LF_ARGLIST
+# CHECK-NEXT:       ArgList:
+# CHECK-NEXT:         ArgIndices:      [ 0 ]
+# CHECK-NEXT:     - Kind:            LF_PROCEDURE
+# CHECK-NEXT:       Procedure:
+# CHECK-NEXT:         ReturnType:      116
+# CHECK-NEXT:         CallConv:        NearC
+# CHECK-NEXT:         Options:         [ None ]
+# CHECK-NEXT:         ParameterCount:  0
+# CHECK-NEXT:         ArgumentList:    4099
+# CHECK-NEXT: IpiStream:
+# CHECK-NEXT:   Version:         VC80
+# CHECK-NEXT:   Records:
+# CHECK-NEXT:     - Kind:            LF_FUNC_ID
+# CHECK-NEXT:       FuncId:
+# CHECK-NEXT:         ParentScope:     0
+# CHECK-NEXT:         FunctionType:    4100
+# CHECK-NEXT:         Name:            main
+# CHECK-NEXT:     - Kind:            LF_FUNC_ID
+# CHECK-NEXT:       FuncId:
+# CHECK-NEXT:         ParentScope:     0
+# CHECK-NEXT:         FunctionType:    4097
+# CHECK-NEXT:         Name:            foo
+# CHECK-NEXT:     - Kind:            LF_STRING_ID
+# CHECK-NEXT:       StringId:
+# CHECK-NEXT:         Id:              0
+# CHECK-NEXT:         String:          'D:\b'
+# CHECK-NEXT:     - Kind:            LF_STRING_ID
+# CHECK-NEXT:       StringId:
+# CHECK-NEXT:         Id:              0
+# CHECK-NEXT:         String:          'C:\vs14\VC\BIN\amd64\cl.exe'
+# CHECK-NEXT:     - Kind:            LF_STRING_ID
+# CHECK-NEXT:       StringId:
+# CHECK-NEXT:         Id:              0
+# CHECK-NEXT:         String:          '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"'
+# CHECK-NEXT:     - Kind:            LF_SUBSTR_LIST
+# CHECK-NEXT:       StringList:
+# CHECK-NEXT:         StringIndices:   [ 4100 ]
+# CHECK-NEXT:     - Kind:            LF_STRING_ID
+# CHECK-NEXT:       StringId:
+# CHECK-NEXT:         Id:              4101
+# CHECK-NEXT:         String:          ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X'
+# CHECK-NEXT:     - Kind:            LF_STRING_ID
+# CHECK-NEXT:       StringId:
+# CHECK-NEXT:         Id:              0
+# CHECK-NEXT:         String:          ret42-main.c
+# CHECK-NEXT:     - Kind:            LF_STRING_ID
+# CHECK-NEXT:       StringId:
+# CHECK-NEXT:         Id:              0
+# CHECK-NEXT:         String:          'D:\b\vc140.pdb'
+# CHECK-NEXT:     - Kind:            LF_BUILDINFO
+# CHECK-NEXT:       BuildInfo:
+# CHECK-NEXT:         ArgIndices:      [ 4098, 4099, 4103, 4104, 4102 ]
+# CHECK-NEXT:     - Kind:            LF_STRING_ID
+# CHECK-NEXT:       StringId:
+# CHECK-NEXT:         Id:              0
+# CHECK-NEXT:         String:          ret42-sub.c
+# CHECK-NEXT:     - Kind:            LF_BUILDINFO
+# CHECK-NEXT:       BuildInfo:
+# CHECK-NEXT:         ArgIndices:      [ 4098, 4099, 4106, 4104, 4102 ]
+
+RAW:                               Modules
+RAW-NEXT: ============================================================
+RAW-NEXT:   Mod 0000 | Name: `{{.*}}pdb.test.tmp1.obj`:
+RAW-NEXT:              Obj: `{{.*}}pdb.test.tmp1.obj`:
+RAW-NEXT:              debug stream: 9, # files: 1, has ec info: false
+RAW-NEXT:              pdb file ni: 0 ``, src file ni: 0 ``
+RAW-NEXT:   Mod 0001 | Name: `{{.*}}pdb.test.tmp2.obj`:
+RAW-NEXT:              Obj: `{{.*}}pdb.test.tmp2.obj`:
+RAW-NEXT:              debug stream: 10, # files: 1, has ec info: false
+RAW-NEXT:              pdb file ni: 0 ``, src file ni: 0 ``
+RAW-NEXT:   Mod 0002 | Name: `* Linker *`:
+RAW-NEXT:              Obj: ``:
+RAW-NEXT:              debug stream: 11, # files: 0, has ec info: false
+RAW-NEXT:              pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 ``
+RAW:                          Types (TPI Stream)
+RAW-NEXT: ============================================================
+RAW-NEXT:   Showing 5 records
+RAW-NEXT:   0x1000 | LF_ARGLIST [size = 8]
+RAW-NEXT:   0x1001 | LF_PROCEDURE [size = 16]
+RAW-NEXT:            return type = 0x0074 (int), # args = 0, param list = 0x1000
+RAW-NEXT:            calling conv = cdecl, options = None
+RAW-NEXT:   0x1002 | LF_POINTER [size = 12]
+RAW-NEXT:            referent = 0x1001, mode = pointer, opts = None, kind = ptr64
+RAW-NEXT:   0x1003 | LF_ARGLIST [size = 12]
+RAW-NEXT:            <no type>: ``
+RAW-NEXT:   0x1004 | LF_PROCEDURE [size = 16]
+RAW-NEXT:            return type = 0x0074 (int), # args = 0, param list = 0x1003
+RAW-NEXT:            calling conv = cdecl, options = None
+RAW:                          Types (IPI Stream)
+RAW-NEXT: ============================================================
+RAW-NEXT:   Showing 12 records
+RAW-NEXT:   0x1000 | LF_FUNC_ID [size = 20]
+RAW-NEXT:            name = main, type = 0x1004, parent scope = <no type>
+RAW-NEXT:   0x1001 | LF_FUNC_ID [size = 16]
+RAW-NEXT:            name = foo, type = 0x1001, parent scope = <no type>
+RAW-NEXT:   0x1002 | LF_STRING_ID [size = 16] ID: <no type>, String: D:\b
+RAW-NEXT:   0x1003 | LF_STRING_ID [size = 36] ID: <no type>, String: C:\vs14\VC\BIN\amd64\cl.exe
+RAW-NEXT:   0x1004 | LF_STRING_ID [size = 260] ID: <no type>, String: -Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"
+RAW-NEXT:   0x1005 | LF_SUBSTR_LIST [size = 12]
+RAW-NEXT:            0x1004: `-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"`
+RAW-NEXT:   0x1006 | LF_STRING_ID [size = 132] ID: 0x1005, String:  -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X
+RAW-NEXT:   0x1007 | LF_STRING_ID [size = 24] ID: <no type>, String: ret42-main.c
+RAW-NEXT:   0x1008 | LF_STRING_ID [size = 24] ID: <no type>, String: D:\b\vc140.pdb
+RAW-NEXT:   0x1009 | LF_BUILDINFO [size = 28]
+RAW-NEXT:            0x1002: `D:\b`
+RAW-NEXT:            0x1003: `C:\vs14\VC\BIN\amd64\cl.exe`
+RAW-NEXT:            0x1007: `ret42-main.c`
+RAW-NEXT:            0x1008: `D:\b\vc140.pdb`
+RAW-NEXT:            0x1006: ` -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X`
+RAW-NEXT:   0x100A | LF_STRING_ID [size = 20] ID: <no type>, String: ret42-sub.c
+RAW-NEXT:   0x100B | LF_BUILDINFO [size = 28]
+RAW-NEXT:            0x1002: `D:\b`
+RAW-NEXT:            0x1003: `C:\vs14\VC\BIN\amd64\cl.exe`
+RAW-NEXT:            0x100A: `ret42-sub.c`
+RAW-NEXT:            0x1008: `D:\b\vc140.pdb`
+RAW-NEXT:            0x1006: ` -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X`
+RAW:                        Section Contributions
+RAW-NEXT: ============================================================
+RAW-NEXT:   SC  | mod = 0, 65535:1288, size = 14, data crc = 0, reloc crc = 0
+RAW-NEXT:         IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+RAW-NEXT:         IMAGE_SCN_MEM_READ
+RAW-NEXT:   SC  | mod = 0, 65535:1312, size = 8, data crc = 0, reloc crc = 0
+RAW-NEXT:         IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
+RAW-NEXT:   SC  | mod = 0, 65535:1320, size = 12, data crc = 0, reloc crc = 0
+RAW-NEXT:         IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ
+RAW-NEXT:   SC  | mod = 1, 65535:1144, size = 6, data crc = 0, reloc crc = 0
+RAW-NEXT:         IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+RAW-NEXT:         IMAGE_SCN_MEM_READ
+RAW:                             Section Map
+RAW-NEXT: ============================================================
+RAW-NEXT:   Section 0000 | ovl = 0, group = 0, frame = 0, name = 1
+RAW-NEXT:                  class = 65535, offset = 0, size =
+RAW-NEXT:                  flags = read | 32 bit addr | selector
+RAW-NEXT:   Section 0001 | ovl = 1, group = 0, frame = 0, name = 2
+RAW-NEXT:                  class = 65535, offset = 0, size =
+RAW-NEXT:                  flags = read | execute | 32 bit addr | selector
+RAW-NEXT:   Section 0002 | ovl = 2, group = 0, frame = 0, name = 3
+RAW-NEXT:                  class = 65535, offset = 0, size =
+RAW-NEXT:                  flags = read | 32 bit addr | selector
+RAW-NEXT:   Section 0003 | ovl = 3, group = 0, frame = 0, name = 4
+RAW-NEXT:                  class = 65535, offset = 0, size =
+RAW-NEXT:                  flags = read | 32 bit addr | selector
+RAW-NEXT:   Section 0004 | ovl = 4, group = 0, frame = 0, name = 5
+RAW-NEXT:                  class = 65535, offset = 0, size =
+RAW-NEXT:                  flags = 32 bit addr | absolute addr
diff --git a/test/COFF/reloc-arm.test b/test/COFF/reloc-arm.test
new file mode 100644 (file)
index 0000000..1f3de61
--- /dev/null
@@ -0,0 +1,84 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: .text:
+# CHECK: 402000 01104000 00000000 00000000 00000000
+# CHECK: 402010 01100000 00000000 00000000 00000000
+# CHECK: 402020 41f20009 c0f24009 00000000 00000000
+# CHECK: 402030 fe07e62f 00000000 00000000 00000000
+# CHECK: 402040 3e04de2f 00000000 00000000 00000000
+# CHECK: 402050 fe07d62f 00000000 00000000 00000000
+# CHECK: 402060 fef0cef7 00000000 00000000 00000000
+# CHECK: 402070 00005000 00000000 00000000 00000000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_ARMNT
+  Characteristics: []
+sections:
+  - Name:            .aaa
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     00000000000000000000000000000000000000000000000000000000000000004ff6ff79cff6ff79000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000f800000000000000000000000000000000000000000000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      foo
+        Type:            1  # IMAGE_REL_ARM_ADDR32
+      - VirtualAddress:  16
+        SymbolName:      foo
+        Type:            2  # IMAGE_REL_ARM_ADDR32NB
+      - VirtualAddress:  32
+        SymbolName:      foo
+        Type:            17  # IMAGE_REL_ARM_MOV32T
+      - VirtualAddress:  48
+        SymbolName:      foo
+        Type:            20  # IMAGE_REL_ARM_BRANCH24T
+      - VirtualAddress:  64
+        SymbolName:      foo
+        Type:            18  # IMAGE_REL_ARM_BRANCH20T
+      - VirtualAddress:  80
+        SymbolName:      foo
+        Type:            21  # IMAGE_REL_ARM_BLX23T
+      - VirtualAddress:  96
+        SymbolName:      bar
+        Type:            20  # IMAGE_REL_ARM_BRANCH24T
+      - VirtualAddress:  112
+        SymbolName:      bar
+        Type:            15  # IMAGE_REL_ARM_SECREL
+symbols:
+  - Name:            .aaa
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            bar
+    Value:           0x500000
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/reloc-discarded-dwarf.s b/test/COFF/reloc-discarded-dwarf.s
new file mode 100644 (file)
index 0000000..d779d2f
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t1.obj %s
+# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t2.obj %s
+
+# LLD should not error on relocations in DWARF debug sections against symbols in
+# discarded sections.
+# RUN: lld-link -entry:main -debug %t1.obj %t2.obj
+
+       .section        .text,"xr",discard,main
+       .globl  main
+main:
+f:
+       retq
+
+       .section        .debug_info,"dr"
+       .quad   f
diff --git a/test/COFF/reloc-discarded.s b/test/COFF/reloc-discarded.s
new file mode 100644 (file)
index 0000000..94eaba9
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: echo -e '.section .bss,"bw",discard,main_global\n.global main_global\n main_global:\n .long 0' | \
+# RUN:     llvm-mc - -filetype=obj -o %t1.obj -triple x86_64-windows-msvc
+# RUN: llvm-mc %s -filetype=obj -o %t2.obj -triple x86_64-windows-msvc
+
+# LLD should report an error and not assert regardless of whether we are doing
+# GC.
+
+# RUN: not lld-link -entry:main -nodefaultlib %t1.obj %t2.obj -out:%t.exe -opt:ref   2>&1 | FileCheck %s
+# RUN: not lld-link -entry:main -nodefaultlib %t1.obj %t2.obj -out:%t.exe -opt:noref 2>&1 | FileCheck %s
+
+# CHECK: error: relocation against symbol in discarded section: assoc_global
+
+       .section        .bss,"bw",discard,main_global
+       .globl  main_global
+       .p2align        2
+main_global:
+       .long   0
+
+       .section        .CRT$XCU,"dr",associative,main_global
+       .p2align        3
+       .globl assoc_global
+assoc_global:
+       .quad   main_global
+
+       .text
+       .globl main
+main:
+       movq assoc_global(%rip), %rax
+       movl (%rax), %eax
+       retq
diff --git a/test/COFF/reloc-oob.yaml b/test/COFF/reloc-oob.yaml
new file mode 100644 (file)
index 0000000..0ed4c4d
--- /dev/null
@@ -0,0 +1,62 @@
+# Make sure LLD does some light relocation bounds checking.
+
+# RUN: yaml2obj %s -o %t.obj
+# RUN: not lld-link %t.obj -entry:main -nodefaultlib -out:%t.exe 2>&1 | FileCheck %s
+
+# CHECK: error: relocation points beyond the end of its parent section
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     5589E550C745FC00000000A10000000083C4045DC3
+    Relocations:
+      - VirtualAddress:  24
+        SymbolName:      _g
+        Type:            IMAGE_REL_I386_DIR32
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     2A000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          21
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        662775349
+      Number:          1
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        3482275674
+      Number:          2
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _g
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/reloc-x64.test b/test/COFF/reloc-x64.test
new file mode 100644 (file)
index 0000000..7af8fb2
--- /dev/null
@@ -0,0 +1,102 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: .text:
+# CHECK: 1000: a1 03 20 00 40 00 00 00 00
+# CHECK: 1009: a1 03 20 00 40 01 00 00 00
+# CHECK: 1012: a1 03 20 00 00 00 00 00 00
+# CHECK: 101b: a1 e3 0f 00 00 00 00 00 00
+# CHECK: 1024: a1 d9 0f 00 00 00 00 00 00
+# CHECK: 102d: a1 cf 0f 00 00 00 00 00 00
+# CHECK: 1036: a1 c5 0f 00 00 00 00 00 00
+# CHECK: 103f: a1 bb 0f 00 00 00 00 00 00
+# CHECK: 1048: a1 b1 0f 00 00 00 00 00 00
+# CHECK: 1051: a1 02 00 00 00 00 00 00 00
+# CHECK: 105a: a1 03 00 00 00 00 00 00 00
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000A10000000000000000
+    Relocations:
+      - VirtualAddress:  1
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_ADDR32
+      - VirtualAddress:  10
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  19
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  28
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  37
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_1
+      - VirtualAddress:  46
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_2
+      - VirtualAddress:  55
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_3
+      - VirtualAddress:  64
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_4
+      - VirtualAddress:  73
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_REL32_5
+      - VirtualAddress:  82
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECTION
+      - VirtualAddress:  91
+        SymbolName:      foo
+        Type:            IMAGE_REL_AMD64_SECREL
+  - Name:            .zzz
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .zzz
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            foo
+    Value:           3
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/reloc-x86.test b/test/COFF/reloc-x86.test
new file mode 100644 (file)
index 0000000..5e14069
--- /dev/null
@@ -0,0 +1,82 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /base:0x400000 %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: .text:
+# CHECK: 1000: a1 00 00 00 00
+# CHECK: 1005: a1 03 20 40 00
+# CHECK: 100a: a1 03 20 00 00
+# CHECK: 100f: a1 ef 0f 00 00
+# CHECK: 1014: a1 00 00 02 00
+# CHECK: 1019: a1 03 00 00 00
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     A100000000A100000000A100000000A100000000A100000000A100000000
+    Relocations:
+      - VirtualAddress:  1
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_ABSOLUTE
+      - VirtualAddress:  6
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  11
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_DIR32NB
+      - VirtualAddress:  16
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_REL32
+      - VirtualAddress:  23
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_SECTION
+      - VirtualAddress:  26
+        SymbolName:      _foo
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .zzz
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4096
+    SectionData:     0000000000000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .zzz
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _foo
+    Value:           3
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/resource.test b/test/COFF/resource.test
new file mode 100644 (file)
index 0000000..53242cd
--- /dev/null
@@ -0,0 +1,44 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res
+
+# Check if the binary contains UTF-16LE string "Hello" copied from resource.res.
+# RUN: FileCheck --check-prefix=EXE %s < %t.exe
+
+EXE: {{H.e.l.l.o}}
+
+# Verify the resource tree layout in the final executable.
+# RUN: llvm-readobj -file-headers -coff-resources -section-data %t.exe | \
+# RUN:   FileCheck --check-prefix=RESOURCE_INFO %s
+
+RESOURCE_INFO:      ResourceTableRVA: 0x1000
+RESOURCE_INFO-NEXT: ResourceTableSize: 0x88
+RESOURCE_INFO-DAG:  Resources [
+RESOURCE_INFO-NEXT:   Total Number of Resources: 1
+RESOURCE_INFO-NEXT:   Base Table Address: 0x400
+RESOURCE_INFO-DAG:    Number of String Entries: 0
+RESOURCE_INFO-NEXT:   Number of ID Entries: 1
+RESOURCE_INFO-NEXT:   Type: kRT_STRING (ID 6) [
+RESOURCE_INFO-NEXT:     Table Offset: 0x18
+RESOURCE_INFO-NEXT:     Number of String Entries: 0
+RESOURCE_INFO-NEXT:     Number of ID Entries: 1
+RESOURCE_INFO-NEXT:     Name: (ID 1) [
+RESOURCE_INFO-NEXT:       Table Offset: 0x30
+RESOURCE_INFO-NEXT:       Number of String Entries: 0
+RESOURCE_INFO-NEXT:       Number of ID Entries: 1
+RESOURCE_INFO-NEXT:       Language: (ID 1033) [
+RESOURCE_INFO-NEXT:         Entry Offset: 0x48
+RESOURCE_INFO-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+RESOURCE_INFO-NEXT:         Major Version: 0
+RESOURCE_INFO-NEXT:         Minor Version: 0
+RESOURCE_INFO-NEXT:         Characteristics: 0
+RESOURCE_INFO-DAG: .rsrc Data (
+RESOURCE_INFO-NEXT: 0000: 00000000 00000000 00000000 00000100  |................|
+RESOURCE_INFO-NEXT: 0010: 06000000 18000080 00000000 00000000  |................|
+RESOURCE_INFO-NEXT: 0020: 00000000 00000100 01000000 30000080  |............0...|
+RESOURCE_INFO-NEXT: 0030: 00000000 00000000 00000000 00000100  |................|
+RESOURCE_INFO-NEXT: 0040: 09040000 48000000 58100000 2A000000  |....H...X...*...|
+RESOURCE_INFO-NEXT: 0050: 00000000 00000000 00000500 48006500  |............H.e.|
+RESOURCE_INFO-NEXT: 0060: 6C006C00 6F000000 00000000 00000000  |l.l.o...........|
+RESOURCE_INFO-NEXT: 0070: 00000000 00000000 00000000 00000000  |................|
+RESOURCE_INFO-NEXT: 0080: 00000000 00000000                    |........|
+RESOURCE_INFO-NEXT: )
diff --git a/test/COFF/responsefile.test b/test/COFF/responsefile.test
new file mode 100644 (file)
index 0000000..fd4d221
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: echo /out:%t.exe /entry:main %t.obj > %t.rsp
+# RUN: lld-link @%t.rsp /heap:0x3000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: SizeOfHeapReserve: 12288
diff --git a/test/COFF/rsds.test b/test/COFF/rsds.test
new file mode 100644 (file)
index 0000000..82b0f22
--- /dev/null
@@ -0,0 +1,94 @@
+# RUN: yaml2obj %s > %t.obj
+
+# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck %s
+
+# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck %s
+
+# CHECK: DebugDirectory [
+# CHECK:   DebugEntry {
+# CHECK:     Characteristics: 0x0
+# CHECK:     TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+# CHECK:     MajorVersion: 0x0
+# CHECK:     MinorVersion: 0x0
+# CHECK:     Type: CodeView (0x2)
+# CHECK:     SizeOfData:
+# CHECK:     AddressOfRawData:
+# CHECK:     PointerToRawData:
+# CHECK:     PDBInfo {
+# CHECK:       PDBSignature: 0x53445352
+# CHECK:       PDBGUID:
+# CHECK:       PDBAge: 1
+# CHECK:       PDBFileName: {{.*}}.pdb
+# CHECK:     }
+# CHECK:   }
+# CHECK: ]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     31C0C3
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          3
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        3963538403
+      Number:          1
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            '@feat.00'
+    Value:           1
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            _DllMain
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/safeseh-diag-feat.test b/test/COFF/safeseh-diag-feat.test
new file mode 100644 (file)
index 0000000..ed928a5
--- /dev/null
@@ -0,0 +1,51 @@
+# RUN: sed s/FEAT_VALUE/1/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj
+
+# RUN: sed s/FEAT_VALUE/0/ %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe /subsystem:console /entry:main \
+# RUN:   /safeseh %t.obj >& %t.log
+# RUN: FileCheck %s < %t.log
+
+# CHECK: /safeseh: {{.*}} is not compatible with SEH
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     0000000000000000
+symbols:
+  - Name:            '@comp.id'
+    Value:           14766605
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           FEAT_VALUE
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/safeseh.s b/test/COFF/safeseh.s
new file mode 100644 (file)
index 0000000..83c15af
--- /dev/null
@@ -0,0 +1,60 @@
+# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC
+# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:ref -entry:main
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC
+
+# CHECK-NOGC: LoadConfig [
+# CHECK-NOGC:   Size: 0x48
+# CHECK-NOGC:   SEHandlerTable: 0x401048
+# CHECK-NOGC:   SEHandlerCount: 1
+# CHECK-NOGC: ]
+# CHECK-NOGC: SEHTable [
+# CHECK-NOGC-NEXT:   0x402006
+# CHECK-NOGC-NEXT: ]
+
+# CHECK-GC: LoadConfig [
+# CHECK-GC:   Size: 0x48
+# CHECK-GC:   SEHandlerTable: 0x0
+# CHECK-GC:   SEHandlerCount: 0
+# CHECK-GC: ]
+# CHECK-GC-NOT: SEHTable
+
+
+        .def     @feat.00;
+        .scl    3;
+        .type   0;
+        .endef
+        .globl  @feat.00
+@feat.00 = 1
+
+        .def     _main;
+        .scl    2;
+        .type   32;
+        .endef
+        .section        .text,"xr",one_only,_main
+        .globl  _main
+_main:
+        movl $42, %eax
+        ret
+
+# This handler can be GCd, which will make the safeseh table empty, so it should
+# appear null.
+        .def     _my_handler;
+        .scl    3;
+        .type   32;
+        .endef
+        .section        .text,"xr",one_only,_my_handler
+_my_handler:
+        ret
+
+.safeseh _my_handler
+
+
+        .section .rdata,"dr"
+.globl __load_config_used
+__load_config_used:
+        .long 72
+        .fill 60, 1, 0
+        .long ___safe_se_handler_table
+        .long ___safe_se_handler_count
diff --git a/test/COFF/savetemps.ll b/test/COFF/savetemps.ll
new file mode 100644 (file)
index 0000000..7f2e11c
--- /dev/null
@@ -0,0 +1,29 @@
+; REQUIRES: x86
+; RUN: rm -fr %T/savetemps
+; RUN: mkdir %T/savetemps
+; RUN: llvm-as -o %T/savetemps/savetemps.obj %s
+; RUN: lld-link /out:%T/savetemps/savetemps.exe /entry:main \
+; RUN:     /subsystem:console %T/savetemps/savetemps.obj
+; RUN: not llvm-dis -o - %T/savetemps/savetemps.exe.0.0.preopt.bc
+; RUN: not llvm-dis -o - %T/savetemps/savetemps.exe.0.2.internalize.bc
+; RUN: not llvm-dis -o - %T/savetemps/savetemps.exe.0.4.opt.bc
+; RUN: not llvm-dis -o - %T/savetemps/savetemps.exe.0.5.precodegen.bc
+; RUN: not llvm-objdump -s %T/savetemps/savetemps.exe.lto.obj
+; RUN: lld-link /lldsavetemps /out:%T/savetemps/savetemps.exe /entry:main \
+; RUN:     /subsystem:console %T/savetemps/savetemps.obj
+; RUN: llvm-dis -o - %T/savetemps/savetemps.exe.0.0.preopt.bc | FileCheck %s
+; RUN: llvm-dis -o - %T/savetemps/savetemps.exe.0.2.internalize.bc | FileCheck %s
+; RUN: llvm-dis -o - %T/savetemps/savetemps.exe.0.4.opt.bc | FileCheck %s
+; RUN: llvm-dis -o - %T/savetemps/savetemps.exe.0.5.precodegen.bc | FileCheck %s
+; RUN: llvm-objdump -s %T/savetemps/savetemps.exe.lto.obj | \
+; RUN:     FileCheck --check-prefix=CHECK-OBJDUMP %s
+
+; CHECK: define i32 @main()
+; CHECK-OBJDUMP: file format COFF
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @main() {
+  ret i32 0
+}
diff --git a/test/COFF/secidx-absolute.s b/test/COFF/secidx-absolute.s
new file mode 100644 (file)
index 0000000..bfe7136
--- /dev/null
@@ -0,0 +1,33 @@
+# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj
+# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe
+# RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s
+
+# Section relocations against absolute symbols resolve to the last real ouput
+# section index plus one.
+
+.text
+.global main
+main:
+ret
+
+.section .rdata,"dr"
+.secidx __guard_fids_table
+
+# CHECK: Sections [
+# CHECK:   Section {
+# CHECK:     Number: 1
+# CHECK:     Name: .rdata (2E 72 64 61 74 61 00 00)
+# CHECK:     SectionData (
+# CHECK:       0000: 0300                                 |..|
+# CHECK:     )
+# CHECK:   }
+# CHECK:   Section {
+# CHECK:     Number: 2
+# CHECK:     Name: .text (2E 74 65 78 74 00 00 00)
+# CHECK:     VirtualSize: 0x1
+# CHECK:     SectionData (
+# CHECK:       0000: C3                                   |.|
+# CHECK:     )
+# CHECK:   }
+# CHECK-NOT: Section
+# CHECK: ]
diff --git a/test/COFF/secrel-absolute.s b/test/COFF/secrel-absolute.s
new file mode 100644 (file)
index 0000000..bc61fb9
--- /dev/null
@@ -0,0 +1,14 @@
+# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj
+# RUN: not lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe 2>&1 | FileCheck %s
+
+# secrel relocations against absolute symbols are errors.
+
+# CHECK: SECREL relocation cannot be applied to absolute symbols
+
+.text
+.global main
+main:
+ret
+
+.section .rdata,"dr"
+.secrel32 __guard_fids_table
diff --git a/test/COFF/secrel-common.s b/test/COFF/secrel-common.s
new file mode 100644 (file)
index 0000000..0188f6c
--- /dev/null
@@ -0,0 +1,41 @@
+# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj
+# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe
+# RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s
+
+# Section relocations against common symbols resolve to .bss.
+
+# CHECK: Sections [
+# CHECK:   Section {
+# CHECK:     Number: 1
+# CHECK:     Name: .bss (2E 62 73 73 00 00 00 00)
+# CHECK:     VirtualSize: 0x4
+# CHECK:   }
+# CHECK:   Section {
+# CHECK:     Number: 2
+# CHECK:     Name: .rdata (2E 72 64 61 74 61 00 00)
+# CHECK:     SectionData (
+# CHECK:       0000: 00000000 01000000 |........|
+# CHECK:     )
+# CHECK:   }
+# CHECK:   Section {
+# CHECK:     Number: 3
+# CHECK:     Name: .text (2E 74 65 78 74 00 00 00)
+# CHECK:     VirtualSize: 0x1
+# CHECK:     SectionData (
+# CHECK:       0000: C3                                   |.|
+# CHECK:     )
+# CHECK:   }
+# CHECK-NOT: Section
+# CHECK: ]
+
+.text
+.global main
+main:
+ret
+
+.comm   common_global,4,2
+
+.section .rdata,"dr"
+.secrel32 common_global
+.secidx common_global
+.short 0
diff --git a/test/COFF/section.test b/test/COFF/section.test
new file mode 100644 (file)
index 0000000..591c04d
--- /dev/null
@@ -0,0 +1,62 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,r %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=R %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,w %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=W %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,e %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=E %s
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \
+# RUN:   /section:.foo,s %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=S %s
+
+# R:      Characteristics [
+# R-NEXT:   IMAGE_SCN_MEM_READ
+# R-NEXT: ]
+
+# W:      Characteristics [
+# W-NEXT:   IMAGE_SCN_MEM_WRITE
+# W-NEXT: ]
+
+# E:      Characteristics [
+# E-NEXT:   IMAGE_SCN_MEM_EXECUTE
+# E-NEXT: ]
+
+# S:      Characteristics [
+# S-NEXT:   IMAGE_SCN_MEM_SHARED
+# S-NEXT: ]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .foo
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     000000000000
+symbols:
+  - Name:            .foo
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/seh.test b/test/COFF/seh.test
new file mode 100644 (file)
index 0000000..f2d0af7
--- /dev/null
@@ -0,0 +1,70 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /subsystem:console /entry:main %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .rdata:
+# CHECK:  1000 00200000 02200000
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     0000000000000000
+  - Name:            .sxdata
+    Characteristics: [ IMAGE_SCN_LNK_INFO ]
+    Alignment:       4
+    SectionData:     0600000007000000
+symbols:
+  - Name:            '@comp.id'
+    Value:           14766605
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           2147484049
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .sxdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _foo
+    Value:           2
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/sort-debug.test b/test/COFF/sort-debug.test
new file mode 100644 (file)
index 0000000..3bad013
--- /dev/null
@@ -0,0 +1,335 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+# CHECK: Name: .text
+# CHECK: Name: .debug_abbrev
+# CHECK: Name: .debug_info
+# CHECK: Name: .debug_line
+# CHECK: Name: .debug_pubnames
+# CHECK: Name: .debug_pubtypes
+# CHECK: Name: .reloc
+
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     508D0500000000C70424000000005AC3
+    Relocations:
+      - VirtualAddress:  3
+        SymbolName:      '?x@@3HA'
+        Type:            IMAGE_REL_I386_DIR32
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            .bss
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     ''
+  - Name:            '.debug$S'
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    Subsections:
+      - !Symbols
+        Records:
+          - Kind:            S_GPROC32_ID
+            ProcSym:
+              PtrParent:       0
+              PtrEnd:          0
+              PtrNext:         0
+              CodeSize:        16
+              DbgStart:        0
+              DbgEnd:          0
+              FunctionType:    0
+              Segment:         0
+              Flags:           [  ]
+              DisplayName:     main
+          - Kind:            S_PROC_ID_END
+            ScopeEndSym:
+      - !Lines
+        CodeSize:        16
+        Flags:           [ HasColumnInfo ]
+        RelocOffset:     0
+        RelocSegment:    0
+        Blocks:
+          - FileName:        '\usr\local\google\home\majnemer\llvm\src\tools\lld\<stdin>'
+            Lines:
+              - Offset:          0
+                LineStart:       1
+                IsStatement:     false
+                EndDelta:        0
+            Columns:
+              - StartColumn:     0
+                EndColumn:       0
+      - !FileChecksums
+        Checksums:
+          - FileName:        '\usr\local\google\home\majnemer\llvm\src\tools\lld\<stdin>'
+            Kind:            None
+            Checksum:        ''
+      - !StringTable
+        Strings:
+          - '\usr\local\google\home\majnemer\llvm\src\tools\lld\<stdin>'
+    Relocations:
+      - VirtualAddress:  44
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  48
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECTION
+      - VirtualAddress:  68
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  72
+        SymbolName:      _main
+        Type:            IMAGE_REL_I386_SECTION
+  - Name:            .debug_str
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     ''
+  - Name:            .debug_loc
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     ''
+  - Name:            .debug_abbrev
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     011101250E1305030E10171B0E110112060000023400030E49133F193A0B3B0B02186E0E0000032400030E3E0B0B0B0000042E0011011206E77F194018030E3A0B3B0B49133F19000000
+  - Name:            .debug_info
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     54000000040000000000040100000000040037000000000000003F000000000000001000000002720000003B0000000101050300000000780000000374000000050404000000001000000001548000000001013B00000000
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      .debug_abbrev
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  12
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  18
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  22
+        SymbolName:      .debug_line
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  26
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  30
+        SymbolName:      .text
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  39
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  51
+        SymbolName:      '?x@@3HA'
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  55
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  60
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+      - VirtualAddress:  67
+        SymbolName:      .text
+        Type:            IMAGE_REL_I386_DIR32
+      - VirtualAddress:  77
+        SymbolName:      .debug_str
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .debug_ranges
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     ''
+  - Name:            .debug_pubnames
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     1D00000002000000000058000000420000006D61696E0026000000780000000000
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      .debug_info
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .debug_pubtypes
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     16000000020000000000580000003B000000696E740000000000
+    Relocations:
+      - VirtualAddress:  6
+        SymbolName:      .debug_info
+        Type:            IMAGE_REL_I386_SECREL
+  - Name:            .debug_line
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    Alignment:       1
+    SectionData:     3300000002001E0000000101FB0E0D000101010100000001000001003C737464696E3E000000000000050200000000010AD60202000101
+    Relocations:
+      - VirtualAddress:  43
+        SymbolName:      .text
+        Type:            IMAGE_REL_I386_DIR32
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          16
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            .data
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            .bss
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          188
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          4
+  - Name:            .debug_str
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          133
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          5
+  - Name:            .debug_loc
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          6
+  - Name:            .debug_abbrev
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          74
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          7
+  - Name:            .debug_info
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          88
+      NumberOfRelocations: 12
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          8
+  - Name:            .debug_ranges
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          0
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          9
+  - Name:            .debug_pubnames
+    Value:           0
+    SectionNumber:   10
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          33
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          10
+  - Name:            .debug_pubtypes
+    Value:           0
+    SectionNumber:   11
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          26
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          11
+  - Name:            .debug_line
+    Value:           0
+    SectionNumber:   12
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          55
+      NumberOfRelocations: 1
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          12
+  - Name:            '@feat.00'
+    Value:           1
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?x@@3HA'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/stack.test b/test/COFF/stack.test
new file mode 100644 (file)
index 0000000..df066b1
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT: SizeOfStackReserve: 1048576
+DEFAULT: SizeOfStackCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /stack:0x3000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+# RUN: echo "STACKSIZE 12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: SizeOfStackReserve: 12288
+CHECK1: SizeOfStackCommit: 4096
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /stack:0x5000,0x3000
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+# RUN: echo "STACKSIZE 20480,12288" > %t.def
+# RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: SizeOfStackReserve: 20480
+CHECK2: SizeOfStackCommit: 12288
diff --git a/test/COFF/subsystem-inference.test b/test/COFF/subsystem-inference.test
new file mode 100644 (file)
index 0000000..231fd54
--- /dev/null
@@ -0,0 +1,74 @@
+# RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MAIN %s
+
+# RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WMAIN %s
+
+# RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s
+
+# RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s
+
+# MAIN:     Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WMAIN:    Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WINMAIN:  Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+# WWINMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     B82A000000C3
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          6
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            ENTRYNAME
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            mainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            wmainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            WinMainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            wWinMainCRTStartup
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/subsystem.test b/test/COFF/subsystem.test
new file mode 100644 (file)
index 0000000..5e72706
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: lld-link /entry:main /out:%t.exe /subsystem:windows \
+# RUN:   %p/Inputs/ret42.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: MajorOperatingSystemVersion: 6
+CHECK1: MinorOperatingSystemVersion: 0
+CHECK1: MajorSubsystemVersion: 6
+CHECK1: MinorSubsystemVersion: 0
+CHECK1: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+
+# RUN: lld-link /entry:main /out:%t.exe /subsystem:windows,8.9 \
+# RUN:   %p/Inputs/ret42.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: MajorOperatingSystemVersion: 8
+CHECK2: MinorOperatingSystemVersion: 9
+CHECK2: MajorSubsystemVersion: 8
+CHECK2: MinorSubsystemVersion: 9
+CHECK2: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
diff --git a/test/COFF/symtab.test b/test/COFF/symtab.test
new file mode 100644 (file)
index 0000000..ffaca28
--- /dev/null
@@ -0,0 +1,236 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /debug /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
+# RUN: lld-link /debug /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -symbols %t.exe | FileCheck %s
+
+# RUN: lld-link /debug /nosymtab /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=NO %s
+
+# CHECK:      Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: .text2
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: .data
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .data (1)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: MessageBoxA
+# CHECK-NEXT:     Value: 80
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: ExitProcess
+# CHECK-NEXT:     Value: 64
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: message
+# CHECK-NEXT:     Value: 6
+# CHECK-NEXT:     Section: .text2 (3)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: main
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text (2)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: caption
+# CHECK-NEXT:     Value: 0
+# CHECK-NEXT:     Section: .text2 (3)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: Static (0x3)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: abs_symbol
+# CHECK-NEXT:     Value: 2662186735
+# CHECK-NEXT:     Section: IMAGE_SYM_ABSOLUTE (-1)
+# CHECK-NEXT:     BaseType: Null (0x0)
+# CHECK-NEXT:     ComplexType: Null (0x0)
+# CHECK-NEXT:     StorageClass: External (0x2)
+# CHECK-NEXT:     AuxSymbolCount: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# NO: Symbols [
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .text2
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4096
+    SectionData:     B800000000000000005068000000000000000068000000000000000050E8000000000000000050E8000000000000000050E80000000000000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      abs_symbol
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  7
+        SymbolName:      caption
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  12
+        SymbolName:      message
+        Type:            IMAGE_REL_AMD64_ADDR64
+      - VirtualAddress:  18
+        SymbolName:      MessageBoxA
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  24
+        SymbolName:      ExitProcess
+        Type:            IMAGE_REL_AMD64_REL32
+      - VirtualAddress:  30
+        SymbolName:      __ImageBase
+        Type:            IMAGE_REL_AMD64_ADDR64
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    Alignment:       4
+    SectionData:     48656C6C6F0048656C6C6F20576F726C6400
+symbols:
+  - Name:            "@comp.id"
+    Value:           10394907
+    SectionNumber:   65535
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .text2
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          28
+      NumberOfRelocations: 6
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .data
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          18
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            MessageBoxA
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            ExitProcess
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            message
+    Value:           6
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            caption
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            abs_symbol
+    Value:           0xDEADBEEF
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __ImageBase
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/thinlto-archives.ll b/test/COFF/thinlto-archives.ll
new file mode 100644 (file)
index 0000000..9a47a3a
--- /dev/null
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+; RUN: rm -fr %T/thinlto-archives
+; RUN: mkdir %T/thinlto-archives %T/thinlto-archives/a %T/thinlto-archives/b
+; RUN: opt -thinlto-bc -o %T/thinlto-archives/main.obj %s
+; RUN: opt -thinlto-bc -o %T/thinlto-archives/a/bar.obj %S/Inputs/lto-dep.ll
+; RUN: opt -thinlto-bc -o %T/thinlto-archives/b/bar.obj %S/Inputs/bar.ll
+; RUN: llvm-ar crs %T/thinlto-archives/a.lib %T/thinlto-archives/a/bar.obj
+; RUN: llvm-ar crs %T/thinlto-archives/b.lib %T/thinlto-archives/b/bar.obj
+; RUN: lld-link /out:%T/thinlto-archives/main.exe -entry:main \
+; RUN:     -subsystem:console %T/thinlto-archives/main.obj \
+; RUN:     %T/thinlto-archives/a.lib %T/thinlto-archives/b.lib
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare void @bar()
+declare void @foo()
+
+define i32 @main() {
+  call void @foo()
+  call void @bar()
+  ret i32 0
+}
diff --git a/test/COFF/thinlto-mangled.ll b/test/COFF/thinlto-mangled.ll
new file mode 100644 (file)
index 0000000..8c901cb
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: opt -thinlto-bc %s -o %t.obj
+; RUN: opt -thinlto-bc %S/Inputs/thinlto-mangled-qux.ll -o %T/thinlto-mangled-qux.obj
+; RUN: lld-link -out:%t.exe -entry:main %t.obj %T/thinlto-mangled-qux.obj
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.0.24215"
+
+%"class.bar" = type { i32 (...)**, i8*, i8*, i8*, i32 }
+
+define i32 @main() {
+  ret i32 0
+}
+
+define available_externally zeroext i1 @"\01?x@bar@@UEBA_NXZ"(%"class.bar"* %this) unnamed_addr align 2 {
+  ret i1 false
+}
diff --git a/test/COFF/thinlto.ll b/test/COFF/thinlto.ll
new file mode 100644 (file)
index 0000000..f01d0d8
--- /dev/null
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+; RUN: rm -fr %T/thinlto
+; RUN: mkdir %T/thinlto
+; RUN: opt -thinlto-bc -o %T/thinlto/main.obj %s
+; RUN: opt -thinlto-bc -o %T/thinlto/foo.obj %S/Inputs/lto-dep.ll
+; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj
+; RUN: llvm-nm %T/thinlto/main.exe.lto.obj | FileCheck %s
+
+; CHECK-NOT: U foo
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @main() {
+  call void @foo()
+  ret i32 0
+}
+
+declare void @foo()
diff --git a/test/COFF/tls.test b/test/COFF/tls.test
new file mode 100644 (file)
index 0000000..a577fe8
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: TLSTableRVA: 0x1000
+# CHECK: TLSTableSize: 0x28
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            _tls_used
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/tls32.test b/test/COFF/tls32.test
new file mode 100644 (file)
index 0000000..fa39614
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: TLSTableRVA: 0x1000
+# CHECK: TLSTableSize: 0x18
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: []
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     00000000
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          4
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            _main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __tls_used
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/unwind.test b/test/COFF/unwind.test
new file mode 100644 (file)
index 0000000..2415b05
--- /dev/null
@@ -0,0 +1,198 @@
+# RUN: yaml2obj < %s > %t.obj
+#
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+# RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s
+#
+# HEADER: ExceptionTableRVA: 0x1000
+#
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x2000
+# UNWIND:   End Address: 0x201b
+# UNWIND:   Unwind Info Address: 0x3000
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 1 UNW_ExceptionHandler
+# UNWIND:     Size of prolog: 18
+# UNWIND:     Number of Codes: 8
+# UNWIND:     Frame register: RBX
+# UNWIND:     Frame offset: 0
+# UNWIND:     Unwind Codes:
+# UNWIND:       0x12: UOP_SetFPReg
+# UNWIND:       0x0f: UOP_PushNonVol RBX
+# UNWIND:       0x0e: UOP_SaveXMM128 XMM8 [0x0000]
+# UNWIND:       0x09: UOP_SaveNonVol RSI [0x0010]
+# UNWIND:       0x04: UOP_AllocSmall 24
+# UNWIND:       0x00: UOP_PushMachFrame w/o error code
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x2012
+# UNWIND:   End Address: 0x2012
+# UNWIND:   Unwind Info Address: 0x301c
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 4 UNW_ChainInfo
+# UNWIND:     Size of prolog: 0
+# UNWIND:     Number of Codes: 0
+# UNWIND:     No frame pointer used
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x201b
+# UNWIND:   End Address: 0x201c
+# UNWIND:   Unwind Info Address: 0x302c
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 0
+# UNWIND:     Size of prolog: 0
+# UNWIND:     Number of Codes: 0
+# UNWIND:     No frame pointer used
+# UNWIND: Function Table:
+# UNWIND:   Start Address: 0x201c
+# UNWIND:   End Address: 0x2039
+# UNWIND:   Unwind Info Address: 0x3034
+# UNWIND:     Version: 1
+# UNWIND:     Flags: 0
+# UNWIND:     Size of prolog: 14
+# UNWIND:     Number of Codes: 6
+# UNWIND:     No frame pointer used
+# UNWIND:     Unwind Codes:
+# UNWIND:       0x0e: UOP_AllocLarge 8454128
+# UNWIND:       0x07: UOP_AllocLarge 8190
+# UNWIND:       0x00: UOP_PushMachFrame w/o error code
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     4883EC184889742410440F110424534889E3488D235B4883C418C3C34881ECF0FF00004881ECF0FF80004881C4F0FF80004881C4F0FF0000C3
+  - Name:            .xdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     0912080312030F300E880000096402000422001A000000000000000021000000000000001B000000000000000100000000000000010E06000E11F0FF80000701FE1F001A
+    Relocations:
+      - VirtualAddress:  20
+        SymbolName:      __C_specific_handler
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  32
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  36
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  40
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    Alignment:       4
+    SectionData:     000000001B0000000000000012000000120000001C00000000000000010000002C000000000000001D00000034000000
+    Relocations:
+      - VirtualAddress:  0
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  4
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  8
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  12
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  16
+        SymbolName:      func
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  20
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  24
+        SymbolName:      smallFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  28
+        SymbolName:      smallFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  32
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  36
+        SymbolName:      allocFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  40
+        SymbolName:      allocFunc
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+      - VirtualAddress:  44
+        SymbolName:      .xdata
+        Type:            IMAGE_REL_AMD64_ADDR32NB
+symbols:
+  - Name:            .text
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          57
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          1
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          68
+      NumberOfRelocations: 4
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          2
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          48
+      NumberOfRelocations: 12
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          3
+  - Name:            func
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __C_specific_handler
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            smallFunc
+    Value:           27
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            allocFunc
+    Value:           28
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            main
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            __C_specific_handler
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/version.test b/test/COFF/version.test
new file mode 100644 (file)
index 0000000..69fa933
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT: MajorImageVersion: 0
+DEFAULT: MinorImageVersion: 0
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /version:11
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: MajorImageVersion: 11
+CHECK1: MinorImageVersion: 0
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj /version:11.22
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: MajorImageVersion: 11
+CHECK2: MinorImageVersion: 22
diff --git a/test/COFF/weak-external.test b/test/COFF/weak-external.test
new file mode 100644 (file)
index 0000000..7bdadd9
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external.ll
+# RUN: lld-link /out:%t1.exe /entry:g /subsystem:console %t.obj
+# RUN: lld-link /out:%t2.exe /entry:g /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj
+# RUN: FileCheck %s < %t2.map
+
+# CHECK: lto.tmp
+# CHECK-NEXT: 0 g
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.text'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     00
+symbols:
+  - Name:            'g'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_WEAK_EXTERNAL
+    WeakExternal:
+      TagIndex:        2
+      Characteristics: IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
+  - Name:            'f'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/weak-external2.test b/test/COFF/weak-external2.test
new file mode 100644 (file)
index 0000000..30101d7
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external2.ll
+# RUN: lld-link /out:%t.exe /entry:g /subsystem:console %t.obj %t.lto.obj
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.text'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     00
+symbols:
+  - Name:            'f'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            'g'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_WEAK_EXTERNAL
+    WeakExternal:
+      TagIndex:        0
+      Characteristics: IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
+...
diff --git a/test/COFF/weak-external3.test b/test/COFF/weak-external3.test
new file mode 100644 (file)
index 0000000..a06ce48
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external3.ll
+# RUN: lld-link /out:%t1.exe /entry:f /subsystem:console /lldmap:%t1.map %t.lto.obj
+# RUN: FileCheck --check-prefix=CHECK1 %s < %t1.map
+# RUN: lld-link /out:%t2.exe /entry:f /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj
+# RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map
+
+# CHECK1: lto.tmp
+# CHECK1-NEXT: 0 g
+
+# CHECK2: weak-external3.test.tmp.obj
+# CHECK2-NEXT: 0 f
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            '.text'
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    Alignment:       16
+    SectionData:     00
+symbols:
+  - Name:            'f'
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/Driver/Inputs/libtest.a b/test/Driver/Inputs/libtest.a
new file mode 100644 (file)
index 0000000..8b277f0
--- /dev/null
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/Driver/Inputs/usr/lib/i386/libtest.a b/test/Driver/Inputs/usr/lib/i386/libtest.a
new file mode 100644 (file)
index 0000000..8b277f0
--- /dev/null
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/Driver/Inputs/usr/lib/libtest.a b/test/Driver/Inputs/usr/lib/libtest.a
new file mode 100644 (file)
index 0000000..8b277f0
--- /dev/null
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/ELF/Inputs/aarch64-condb-reloc.s b/test/ELF/Inputs/aarch64-condb-reloc.s
new file mode 100644 (file)
index 0000000..ebe4923
--- /dev/null
@@ -0,0 +1,17 @@
+.globl _foo
+_foo:
+ nop
+ nop
+ nop
+ nop
+
+.globl _bar
+_bar:
+ nop
+ nop
+ nop
+
+.globl _dah
+_dah:
+ nop
+ nop
diff --git a/test/ELF/Inputs/aarch64-copy2.s b/test/ELF/Inputs/aarch64-copy2.s
new file mode 100644 (file)
index 0000000..8f3f748
--- /dev/null
@@ -0,0 +1,5 @@
+        .global foo
+        .type foo, @function
+foo:
+        .global bar
+bar:
diff --git a/test/ELF/Inputs/aarch64-tls-gdie.s b/test/ELF/Inputs/aarch64-tls-gdie.s
new file mode 100644 (file)
index 0000000..289cae5
--- /dev/null
@@ -0,0 +1,4 @@
+        .section        .tdata,"awT",@progbits
+        .globl  a
+a:
+        .word   42
diff --git a/test/ELF/Inputs/aarch64-tls-ie.s b/test/ELF/Inputs/aarch64-tls-ie.s
new file mode 100644 (file)
index 0000000..c5e853b
--- /dev/null
@@ -0,0 +1,19 @@
+.text
+ .global foo
+ .section .tdata,"awT",%progbits
+ .align 2
+ .type foo, %object
+ .size foo, 4
+foo:
+ .word 5
+ .text
+
+.text
+ .global bar
+ .section .tdata,"awT",%progbits
+ .align 2
+ .type bar, %object
+ .size bar, 4
+bar:
+ .word 5
+ .text
diff --git a/test/ELF/Inputs/aarch64-tstbr14-reloc.s b/test/ELF/Inputs/aarch64-tstbr14-reloc.s
new file mode 100644 (file)
index 0000000..64dc440
--- /dev/null
@@ -0,0 +1,12 @@
+.globl _foo
+_foo:
+ nop
+ nop
+ nop
+ nop
+
+.globl _bar
+_bar:
+ nop
+ nop
+ nop
diff --git a/test/ELF/Inputs/abs-hidden.s b/test/ELF/Inputs/abs-hidden.s
new file mode 100644 (file)
index 0000000..44bff38
--- /dev/null
@@ -0,0 +1,3 @@
+.global foo
+.hidden foo
+foo = 0x42
diff --git a/test/ELF/Inputs/abs.s b/test/ELF/Inputs/abs.s
new file mode 100644 (file)
index 0000000..dc7f67a
--- /dev/null
@@ -0,0 +1,4 @@
+.global abs
+abs = 0x42
+.global big
+big = 0x1000000000
diff --git a/test/ELF/Inputs/abs255.s b/test/ELF/Inputs/abs255.s
new file mode 100644 (file)
index 0000000..844ae7d
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo = 255
diff --git a/test/ELF/Inputs/abs256.s b/test/ELF/Inputs/abs256.s
new file mode 100644 (file)
index 0000000..3f53bc5
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo = 256
diff --git a/test/ELF/Inputs/abs257.s b/test/ELF/Inputs/abs257.s
new file mode 100644 (file)
index 0000000..4ae7fe8
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo = 257
diff --git a/test/ELF/Inputs/allow-multiple-definition.s b/test/ELF/Inputs/allow-multiple-definition.s
new file mode 100644 (file)
index 0000000..c2655a4
--- /dev/null
@@ -0,0 +1,4 @@
+.globl _bar
+.type _bar, @function
+_bar:
+  mov $2, %eax
diff --git a/test/ELF/Inputs/allow-shlib-undefined.s b/test/ELF/Inputs/allow-shlib-undefined.s
new file mode 100644 (file)
index 0000000..5e3a461
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _shared
+_shared:
+  callq _unresolved@PLT
diff --git a/test/ELF/Inputs/archive.s b/test/ELF/Inputs/archive.s
new file mode 100644 (file)
index 0000000..568bc1f
--- /dev/null
@@ -0,0 +1,5 @@
+.globl _start
+_start:
+
+.globl end
+end:
diff --git a/test/ELF/Inputs/archive2.s b/test/ELF/Inputs/archive2.s
new file mode 100644 (file)
index 0000000..ade7955
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo:
diff --git a/test/ELF/Inputs/archive3.s b/test/ELF/Inputs/archive3.s
new file mode 100644 (file)
index 0000000..3e11d43
--- /dev/null
@@ -0,0 +1,2 @@
+.global bar
+bar:
diff --git a/test/ELF/Inputs/archive4.s b/test/ELF/Inputs/archive4.s
new file mode 100644 (file)
index 0000000..e842874
--- /dev/null
@@ -0,0 +1 @@
+.quad bar
diff --git a/test/ELF/Inputs/arm-attributes1.s b/test/ELF/Inputs/arm-attributes1.s
new file mode 100644 (file)
index 0000000..da67c49
--- /dev/null
@@ -0,0 +1,29 @@
+// Input that generates an object with a populated SHT_ARM_ATTRIBUTES section
+ .text
+ .syntax unified
+ .eabi_attribute        67, "2.09"      @ Tag_conformance
+ .cpu    cortex-a8
+ .eabi_attribute 6, 10   @ Tag_CPU_arch
+ .eabi_attribute 7, 65   @ Tag_CPU_arch_profile
+ .eabi_attribute 8, 1    @ Tag_ARM_ISA_use
+ .eabi_attribute 9, 2    @ Tag_THUMB_ISA_use
+ .fpu    neon
+ .eabi_attribute 15, 1   @ Tag_ABI_PCS_RW_data
+ .eabi_attribute 16, 1   @ Tag_ABI_PCS_RO_data
+ .eabi_attribute 17, 2   @ Tag_ABI_PCS_GOT_use
+ .eabi_attribute 20, 1   @ Tag_ABI_FP_denormal
+ .eabi_attribute 21, 1   @ Tag_ABI_FP_exceptions
+ .eabi_attribute 23, 3   @ Tag_ABI_FP_number_model
+ .eabi_attribute 34, 1   @ Tag_CPU_unaligned_access
+ .eabi_attribute 24, 1   @ Tag_ABI_align_needed
+ .eabi_attribute 25, 1   @ Tag_ABI_align_preserved
+ .eabi_attribute 38, 1   @ Tag_ABI_FP_16bit_format
+ .eabi_attribute 18, 4   @ Tag_ABI_PCS_wchar_t
+ .eabi_attribute 26, 2   @ Tag_ABI_enum_size
+ .eabi_attribute 14, 0   @ Tag_ABI_PCS_R9_use
+ .eabi_attribute 68, 1   @ Tag_Virtualization_use
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+ bx lr
diff --git a/test/ELF/Inputs/arm-exidx-cantunwind.s b/test/ELF/Inputs/arm-exidx-cantunwind.s
new file mode 100644 (file)
index 0000000..679cc75
--- /dev/null
@@ -0,0 +1,40 @@
+// Functions that will generate a .ARM.exidx section with SHF_LINK_ORDER
+// dependency on the progbits section containing the .cantunwind directive
+ .syntax unified
+ .section .func1, "ax",%progbits
+ .globl func1
+func1:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .func2, "ax", %progbits
+ .globl func2
+func2:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .func3, "ax",%progbits
+ .globl func3
+func3:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text, "ax",%progbits
+ .globl func4
+func4:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+ .globl func5
+func5:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
diff --git a/test/ELF/Inputs/arm-plt-reloc.s b/test/ELF/Inputs/arm-plt-reloc.s
new file mode 100644 (file)
index 0000000..29f133e
--- /dev/null
@@ -0,0 +1,14 @@
+.text
+ .align 2
+ .globl func1
+ .type  func1,%function
+func1:
+ bx lr
+ .globl func2
+ .type  func2,%function
+func2:
+ bx lr
+ .globl func3
+ .type  func3,%function
+func3:
+ bx lr
diff --git a/test/ELF/Inputs/arm-shared.s b/test/ELF/Inputs/arm-shared.s
new file mode 100644 (file)
index 0000000..4330a1d
--- /dev/null
@@ -0,0 +1,8 @@
+.syntax unified
+.global bar2
+.type bar2, %function
+bar2:
+
+.global zed2
+.type zed2, %function
+zed2:
diff --git a/test/ELF/Inputs/arm-thumb-blx-targets.s b/test/ELF/Inputs/arm-thumb-blx-targets.s
new file mode 100644 (file)
index 0000000..4585ac4
--- /dev/null
@@ -0,0 +1,36 @@
+ .syntax unified
+ .arm
+ .section .R_ARM_CALL24_callee_low, "ax",%progbits
+ .align 2
+ .globl callee_low
+ .type callee_low,%function
+callee_low:
+ bx lr
+
+ .section .R_ARM_CALL24_callee_thumb_low, "ax",%progbits
+ .balign 0x100
+ .thumb
+ .type callee_thumb_low,%function
+ .globl callee_thumb_low
+callee_thumb_low:
+  bx lr
+
+ .section .R_ARM_CALL24_callee_high, "ax",%progbits
+ .balign 0x100
+ .arm
+ .globl callee_high
+ .type callee_high,%function
+callee_high:
+ bx lr
+
+ .section .R_ARM_CALL24_callee_thumb_high, "ax",%progbits
+ .balign 0x100
+ .thumb
+ .type callee_thumb_high,%function
+ .globl callee_thumb_high
+callee_thumb_high:
+  bx lr
+
+ .globl blx_far
+ .type   blx_far, %function
+blx_far = 0x1010018
diff --git a/test/ELF/Inputs/arm-thumb-narrow-branch.o b/test/ELF/Inputs/arm-thumb-narrow-branch.o
new file mode 100644 (file)
index 0000000..9816ec7
Binary files /dev/null and b/test/ELF/Inputs/arm-thumb-narrow-branch.o differ
diff --git a/test/ELF/Inputs/arm-thumb-narrow-branch.s b/test/ELF/Inputs/arm-thumb-narrow-branch.s
new file mode 100644 (file)
index 0000000..473a8e6
--- /dev/null
@@ -0,0 +1,18 @@
+// This input must be assembled by the GNU assembler, as llvm-mc does not emit
+// the R_ARM_JUMP11 relocation for a Thumb narrow branch. This is permissible
+// by the ABI for the ARM architecture as the range of the Thumb narrow branch
+// is short enough (+- 2048 bytes) that widespread use would be impractical.
+//
+// The test case will use a pre compiled object arm-thumb-narrow-branch.o
+ .syntax unified
+ .section .caller, "ax",%progbits
+ .thumb
+ .align 2
+ .type callers,%function
+ .globl callers
+callers:
+ b.n callee_low_far
+ b.n callee_low
+ b.n callee_high
+ b.n callee_high_far
+ bx lr
diff --git a/test/ELF/Inputs/arm-tls-get-addr.s b/test/ELF/Inputs/arm-tls-get-addr.s
new file mode 100644 (file)
index 0000000..f3212ad
--- /dev/null
@@ -0,0 +1,13 @@
+ .syntax unified
+ .text
+ .globl __tls_get_addr
+ .type __tls_get_addr,%function
+__tls_get_addr:
+ bx lr
+
+.section       .tbss,"awT",%nobits
+ .p2align  2
+y:
+ .space 4
+ .globl y
+ .type  y, %object
diff --git a/test/ELF/Inputs/bad-archive.a b/test/ELF/Inputs/bad-archive.a
new file mode 100644 (file)
index 0000000..c9c6fbf
--- /dev/null
@@ -0,0 +1,2 @@
+!<arch>
+this is malformed archive used in bad-archive.s
diff --git a/test/ELF/Inputs/comdat.s b/test/ELF/Inputs/comdat.s
new file mode 100644 (file)
index 0000000..467bfa4
--- /dev/null
@@ -0,0 +1,3 @@
+        .section .text3,"axG",@progbits,zed,comdat,unique,0
+        .global abc
+abc:
diff --git a/test/ELF/Inputs/comment-gc.s b/test/ELF/Inputs/comment-gc.s
new file mode 100644 (file)
index 0000000..2453ce9
--- /dev/null
@@ -0,0 +1 @@
+.ident "bar"
diff --git a/test/ELF/Inputs/common.s b/test/ELF/Inputs/common.s
new file mode 100644 (file)
index 0000000..ea8ba91
--- /dev/null
@@ -0,0 +1,3 @@
+.comm sym1,8,4
+.comm sym2,4,4
+.comm sym4,4,16
diff --git a/test/ELF/Inputs/conflict-debug.s b/test/ELF/Inputs/conflict-debug.s
new file mode 100644 (file)
index 0000000..03fb013
--- /dev/null
@@ -0,0 +1,5 @@
+.file 1 "conflict-debug.s"
+.globl zed
+.loc 1 4
+zed:
+  nop
diff --git a/test/ELF/Inputs/conflict.s b/test/ELF/Inputs/conflict.s
new file mode 100644 (file)
index 0000000..545ae99
--- /dev/null
@@ -0,0 +1,7 @@
+.globl _Z3muldd, foo, baz
+_Z3muldd:
+foo:
+baz:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/Inputs/copy-in-shared.s b/test/ELF/Inputs/copy-in-shared.s
new file mode 100644 (file)
index 0000000..52e99c6
--- /dev/null
@@ -0,0 +1,4 @@
+.type foo, @object
+.global foo
+foo:
+.size foo, 4
diff --git a/test/ELF/Inputs/copy-rel-corrupted.s b/test/ELF/Inputs/copy-rel-corrupted.s
new file mode 100644 (file)
index 0000000..b8d1b1a
--- /dev/null
@@ -0,0 +1,4 @@
+.type x,@object
+.globl x
+x:
+.size x, 0
diff --git a/test/ELF/Inputs/copy-rel-pie.s b/test/ELF/Inputs/copy-rel-pie.s
new file mode 100644 (file)
index 0000000..6dac01d
--- /dev/null
@@ -0,0 +1,11 @@
+.data
+.global foo
+.type foo, @object
+.size foo, 4
+foo:
+.long 0
+
+.text
+.global bar
+.type bar, @function
+bar:
diff --git a/test/ELF/Inputs/ctors_dtors_priority1.s b/test/ELF/Inputs/ctors_dtors_priority1.s
new file mode 100644 (file)
index 0000000..2102dba
--- /dev/null
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .quad 0xA1
+
+.section .dtors, "aw", @progbits
+  .quad 0xA2
diff --git a/test/ELF/Inputs/ctors_dtors_priority2.s b/test/ELF/Inputs/ctors_dtors_priority2.s
new file mode 100644 (file)
index 0000000..e94b15e
--- /dev/null
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .quad 0xB1
+
+.section .dtors, "aw", @progbits
+  .quad 0xB2
diff --git a/test/ELF/Inputs/ctors_dtors_priority3.s b/test/ELF/Inputs/ctors_dtors_priority3.s
new file mode 100644 (file)
index 0000000..7bba90c
--- /dev/null
@@ -0,0 +1,5 @@
+.section .ctors, "aw", @progbits
+  .quad 0xC1
+
+.section .dtors, "aw", @progbits
+  .quad 0xC2
diff --git a/test/ELF/Inputs/discard-merge-unnamed.o b/test/ELF/Inputs/discard-merge-unnamed.o
new file mode 100644 (file)
index 0000000..040addf
Binary files /dev/null and b/test/ELF/Inputs/discard-merge-unnamed.o differ
diff --git a/test/ELF/Inputs/dso-undef-size.s b/test/ELF/Inputs/dso-undef-size.s
new file mode 100644 (file)
index 0000000..424f56f
--- /dev/null
@@ -0,0 +1,4 @@
+.text
+.global foo
+.size foo, 4
+foo:
diff --git a/test/ELF/Inputs/dtrace-r.o b/test/ELF/Inputs/dtrace-r.o
new file mode 100644 (file)
index 0000000..ce742de
Binary files /dev/null and b/test/ELF/Inputs/dtrace-r.o differ
diff --git a/test/ELF/Inputs/duplicated-plt-entry.s b/test/ELF/Inputs/duplicated-plt-entry.s
new file mode 100644 (file)
index 0000000..689f3af
--- /dev/null
@@ -0,0 +1,3 @@
+.global bar
+.type bar, @gnu_indirect_function
+bar:
diff --git a/test/ELF/Inputs/dynamic-reloc-weak.s b/test/ELF/Inputs/dynamic-reloc-weak.s
new file mode 100644 (file)
index 0000000..2310749
--- /dev/null
@@ -0,0 +1,11 @@
+        .type sym1,@function
+        .global sym1
+sym1:
+
+        .type sym2,@function
+        .global sym2
+sym2:
+
+        .type sym3,@function
+        .global sym3
+sym3:
diff --git a/test/ELF/Inputs/dynamic-reloc.s b/test/ELF/Inputs/dynamic-reloc.s
new file mode 100644 (file)
index 0000000..82fa7a1
--- /dev/null
@@ -0,0 +1,2 @@
+.global main
+main:
diff --git a/test/ELF/Inputs/eh-frame-end.s b/test/ELF/Inputs/eh-frame-end.s
new file mode 100644 (file)
index 0000000..b7334d8
--- /dev/null
@@ -0,0 +1,2 @@
+       .section ".eh_frame", "a", @progbits
+       .long 0
diff --git a/test/ELF/Inputs/ehframe-relocation.s b/test/ELF/Inputs/ehframe-relocation.s
new file mode 100644 (file)
index 0000000..7ba6c05
--- /dev/null
@@ -0,0 +1,2 @@
+        .cfi_startproc
+        .cfi_endproc
diff --git a/test/ELF/Inputs/empty-ver.ver b/test/ELF/Inputs/empty-ver.ver
new file mode 100644 (file)
index 0000000..7d4b4ed
--- /dev/null
@@ -0,0 +1,2 @@
+ver {
+};
diff --git a/test/ELF/Inputs/exclude-libs.s b/test/ELF/Inputs/exclude-libs.s
new file mode 100644 (file)
index 0000000..6d05c5e
--- /dev/null
@@ -0,0 +1,3 @@
+.globl fn
+fn:
+  nop
diff --git a/test/ELF/Inputs/far-arm-abs.s b/test/ELF/Inputs/far-arm-abs.s
new file mode 100644 (file)
index 0000000..68d6aab
--- /dev/null
@@ -0,0 +1,13 @@
+.global far
+.type far,%function
+far = 0x201001c
+
+.global too_far1
+.type too_far1,%function
+too_far1 = 0x2020008
+.global too_far2
+.type too_far2,%function
+too_far2 = 0x202000c
+.global too_far3
+.type too_far3,%function
+too_far3 = 0x2020010
diff --git a/test/ELF/Inputs/far-arm-thumb-abs.s b/test/ELF/Inputs/far-arm-thumb-abs.s
new file mode 100644 (file)
index 0000000..0eb99b8
--- /dev/null
@@ -0,0 +1,24 @@
+.global far_cond
+.type far_cond,%function
+far_cond = 0x110023
+.global far_uncond
+.type far_uncond,%function
+far_uncond = 0x101001b
+
+.global too_far1
+.type too_far1,%function
+too_far1 = 0x1020005
+.global too_far2
+.type too_far1,%function
+too_far2 = 0x1020009
+.global too_far3
+.type too_far3,%function
+too_far3 = 0x12000d
+
+.global blx_far
+.type   blx_far, %function
+blx_far = 0x2010025
+
+.global blx_far2
+.type   blx_far2, %function
+blx_far2 = 0x2010029
diff --git a/test/ELF/Inputs/gc-sections-weak.s b/test/ELF/Inputs/gc-sections-weak.s
new file mode 100644 (file)
index 0000000..27baa66
--- /dev/null
@@ -0,0 +1,8 @@
+.weak foo
+foo:
+        nop
+
+.data
+.global bar2
+bar2:
+.quad foo
diff --git a/test/ELF/Inputs/gdb-index.s b/test/ELF/Inputs/gdb-index.s
new file mode 100644 (file)
index 0000000..907a66d
--- /dev/null
@@ -0,0 +1,73 @@
+.text
+.Ltext0:
+.globl main2
+.type main2, @function
+main2:
+ nop
+ nop
+.Letext0:
+
+.section .debug_info,"",@progbits
+.long 0x30
+.value 0x4
+.long 0
+.byte 0x8
+.uleb128 0x1
+.quad .Ltext0
+.quad .Letext0-.Ltext0
+.long 0
+.long 0
+.long 0
+.long 0
+.byte 0x63
+.byte 0x88
+.byte 0xb4
+.byte 0x61
+.byte 0xaa
+.byte 0xb6
+.byte 0xb0
+.byte 0x67
+
+.section .debug_abbrev,"",@progbits
+.uleb128 0x1
+.uleb128 0x11
+.byte 0
+.uleb128 0x11
+.uleb128 0x1
+.uleb128 0x12
+.uleb128 0x7
+.uleb128 0x10
+.uleb128 0x17
+.uleb128 0x2130
+.uleb128 0xe
+.uleb128 0x1b
+.uleb128 0xe
+.uleb128 0x2134
+.uleb128 0x19
+.uleb128 0x2133
+.uleb128 0x17
+.uleb128 0x2131
+.uleb128 0x7
+.byte 0
+.byte 0
+.byte 0
+
+.section .debug_gnu_pubnames,"",@progbits
+.long 0x18
+.value 0x2
+.long 0
+.long 0x33
+.long 0x18
+.byte 0x30
+.string "main2"
+.long 0
+
+.section .debug_gnu_pubtypes,"",@progbits
+.long 0x17
+.value 0x2
+.long 0
+.long 0x33
+.long 0x2b
+.byte 0x90
+.string "int"
+.long 0
diff --git a/test/ELF/Inputs/gnu-ifunc-dso.s b/test/ELF/Inputs/gnu-ifunc-dso.s
new file mode 100644 (file)
index 0000000..bd82718
--- /dev/null
@@ -0,0 +1,3 @@
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
diff --git a/test/ELF/Inputs/gnu-ifunc-gotpcrel.s b/test/ELF/Inputs/gnu-ifunc-gotpcrel.s
new file mode 100644 (file)
index 0000000..83b06e0
--- /dev/null
@@ -0,0 +1,4 @@
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ret
diff --git a/test/ELF/Inputs/gotpc-relax-und-dso.s b/test/ELF/Inputs/gotpc-relax-und-dso.s
new file mode 100644 (file)
index 0000000..cbe39f3
--- /dev/null
@@ -0,0 +1,4 @@
+.globl dsofoo
+.type dsofoo, @function
+dsofoo:
+ nop
diff --git a/test/ELF/Inputs/i386-got32x-baseless.elf b/test/ELF/Inputs/i386-got32x-baseless.elf
new file mode 100644 (file)
index 0000000..824d757
Binary files /dev/null and b/test/ELF/Inputs/i386-got32x-baseless.elf differ
diff --git a/test/ELF/Inputs/i386-reloc-16-error.s b/test/ELF/Inputs/i386-reloc-16-error.s
new file mode 100644 (file)
index 0000000..8deed64
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 65536
diff --git a/test/ELF/Inputs/i386-reloc-16.s b/test/ELF/Inputs/i386-reloc-16.s
new file mode 100644 (file)
index 0000000..ac4601b
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 0xffff
diff --git a/test/ELF/Inputs/i386-reloc-8-error.s b/test/ELF/Inputs/i386-reloc-8-error.s
new file mode 100644 (file)
index 0000000..b6a7626
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 256
diff --git a/test/ELF/Inputs/i386-reloc-8.s b/test/ELF/Inputs/i386-reloc-8.s
new file mode 100644 (file)
index 0000000..ce488f6
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 0xff
diff --git a/test/ELF/Inputs/i386-tls-got.s b/test/ELF/Inputs/i386-tls-got.s
new file mode 100644 (file)
index 0000000..42d16b1
--- /dev/null
@@ -0,0 +1,5 @@
+       .type   foobar,@object
+       .section        .tdata,"awT",@progbits
+       .globl  foobar
+foobar:
+       .long   42
diff --git a/test/ELF/Inputs/icf-absolute.s b/test/ELF/Inputs/icf-absolute.s
new file mode 100644 (file)
index 0000000..4c2da9d
--- /dev/null
@@ -0,0 +1,3 @@
+.globl a1, a2
+a1 = 1
+a2 = 1
diff --git a/test/ELF/Inputs/icf-merge-sec.s b/test/ELF/Inputs/icf-merge-sec.s
new file mode 100644 (file)
index 0000000..7454e95
--- /dev/null
@@ -0,0 +1,9 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+.asciz "foo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+.quad .rodata.str+8
diff --git a/test/ELF/Inputs/icf-merge.s b/test/ELF/Inputs/icf-merge.s
new file mode 100644 (file)
index 0000000..8a09929
--- /dev/null
@@ -0,0 +1,10 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+foo:
+.asciz "foo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+lea foo+42(%rip), %rax
diff --git a/test/ELF/Inputs/icf-merge2.s b/test/ELF/Inputs/icf-merge2.s
new file mode 100644 (file)
index 0000000..e845a61
--- /dev/null
@@ -0,0 +1,10 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+boo:
+.asciz "boo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+lea boo+42(%rip), %rax
diff --git a/test/ELF/Inputs/icf-merge3.s b/test/ELF/Inputs/icf-merge3.s
new file mode 100644 (file)
index 0000000..91bf05e
--- /dev/null
@@ -0,0 +1,10 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+foo:
+.asciz "foo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+lea foo+43(%rip), %rax
diff --git a/test/ELF/Inputs/icf-non-mergeable.s b/test/ELF/Inputs/icf-non-mergeable.s
new file mode 100644 (file)
index 0000000..0c42a65
--- /dev/null
@@ -0,0 +1,8 @@
+.globl d1, d2
+.section .data.d1, "aw"
+d1:
+  .quad 0
+
+.section .data.d2, "aw"
+d2:
+  .quad 0
diff --git a/test/ELF/Inputs/icf2.s b/test/ELF/Inputs/icf2.s
new file mode 100644 (file)
index 0000000..d332130
--- /dev/null
@@ -0,0 +1,5 @@
+.globl f1, f2
+.section .text.f2, "ax"
+f2:
+  mov $60, %rdi
+  call f1
diff --git a/test/ELF/Inputs/libsearch-dyn.s b/test/ELF/Inputs/libsearch-dyn.s
new file mode 100644 (file)
index 0000000..091b3b9
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _bar,_dynamic
+_bar:
+_dynamic:
diff --git a/test/ELF/Inputs/libsearch-st.s b/test/ELF/Inputs/libsearch-st.s
new file mode 100644 (file)
index 0000000..6da62f7
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _bar,_static
+_bar:
+_static:
diff --git a/test/ELF/Inputs/llvm33-rela-outside-group.o b/test/ELF/Inputs/llvm33-rela-outside-group.o
new file mode 100644 (file)
index 0000000..70e659f
Binary files /dev/null and b/test/ELF/Inputs/llvm33-rela-outside-group.o differ
diff --git a/test/ELF/Inputs/map-file2.s b/test/ELF/Inputs/map-file2.s
new file mode 100644 (file)
index 0000000..d46b06f
--- /dev/null
@@ -0,0 +1,8 @@
+foo:
+nop
+.global bar
+bar:
+nop
+.section .text.zed,"ax",@progbits
+.global zed
+zed:
diff --git a/test/ELF/Inputs/map-file3.s b/test/ELF/Inputs/map-file3.s
new file mode 100644 (file)
index 0000000..3e869c0
--- /dev/null
@@ -0,0 +1,2 @@
+.global bah
+bah:
diff --git a/test/ELF/Inputs/map-file4.s b/test/ELF/Inputs/map-file4.s
new file mode 100644 (file)
index 0000000..c95ce37
--- /dev/null
@@ -0,0 +1,3 @@
+.global baz
+baz:
+        retq
diff --git a/test/ELF/Inputs/merge.s b/test/ELF/Inputs/merge.s
new file mode 100644 (file)
index 0000000..a8e1144
--- /dev/null
@@ -0,0 +1,6 @@
+        .section        .mysec,"aM",@progbits,4
+        .align  4
+        .long   0x42
+
+        .text
+        movl .mysec, %eax
diff --git a/test/ELF/Inputs/mips-align-err.s b/test/ELF/Inputs/mips-align-err.s
new file mode 100644 (file)
index 0000000..2d813b7
--- /dev/null
@@ -0,0 +1,2 @@
+        .global _foo
+_foo:
diff --git a/test/ELF/Inputs/mips-concatenated-abiflags.o b/test/ELF/Inputs/mips-concatenated-abiflags.o
new file mode 100644 (file)
index 0000000..4045309
Binary files /dev/null and b/test/ELF/Inputs/mips-concatenated-abiflags.o differ
diff --git a/test/ELF/Inputs/mips-dynamic.s b/test/ELF/Inputs/mips-dynamic.s
new file mode 100644 (file)
index 0000000..6f15cf3
--- /dev/null
@@ -0,0 +1,28 @@
+  .option pic2
+  .text
+  .globl _foo
+_foo:
+  nop
+
+  .globl foo0
+  .type foo0, @function
+foo0:
+  nop
+
+  .globl foo1
+  .type foo1, @function
+foo1:
+  nop
+
+  .data
+  .globl data0
+  .type data0, @object
+  .size data0, 4
+data0:
+  .word 0
+
+  .globl data1
+  .type data1, @object
+  .size data1, 4
+data1:
+  .word 0
diff --git a/test/ELF/Inputs/mips-fnpic.s b/test/ELF/Inputs/mips-fnpic.s
new file mode 100644 (file)
index 0000000..d8bf0ba
--- /dev/null
@@ -0,0 +1,6 @@
+  .option pic0
+  .text
+  .global fnpic
+  .type fnpic, @function
+fnpic:
+  nop
diff --git a/test/ELF/Inputs/mips-fpic.s b/test/ELF/Inputs/mips-fpic.s
new file mode 100644 (file)
index 0000000..b7af281
--- /dev/null
@@ -0,0 +1,6 @@
+  .option pic2
+  .text
+  .global fpic
+  .type fpic, @function
+fpic:
+  nop
diff --git a/test/ELF/Inputs/mips-gp-disp.so b/test/ELF/Inputs/mips-gp-disp.so
new file mode 100644 (file)
index 0000000..150de18
Binary files /dev/null and b/test/ELF/Inputs/mips-gp-disp.so differ
diff --git a/test/ELF/Inputs/mips-gp0-non-zero.o b/test/ELF/Inputs/mips-gp0-non-zero.o
new file mode 100755 (executable)
index 0000000..4c82343
Binary files /dev/null and b/test/ELF/Inputs/mips-gp0-non-zero.o differ
diff --git a/test/ELF/Inputs/mips-n32-rels.o b/test/ELF/Inputs/mips-n32-rels.o
new file mode 100644 (file)
index 0000000..88cbce6
Binary files /dev/null and b/test/ELF/Inputs/mips-n32-rels.o differ
diff --git a/test/ELF/Inputs/mips-nonalloc.s b/test/ELF/Inputs/mips-nonalloc.s
new file mode 100644 (file)
index 0000000..72bfd27
--- /dev/null
@@ -0,0 +1,2 @@
+  .section .debug_info
+  .word __start
diff --git a/test/ELF/Inputs/mips-options.o b/test/ELF/Inputs/mips-options.o
new file mode 100644 (file)
index 0000000..ace9385
Binary files /dev/null and b/test/ELF/Inputs/mips-options.o differ
diff --git a/test/ELF/Inputs/mips-pic.s b/test/ELF/Inputs/mips-pic.s
new file mode 100644 (file)
index 0000000..8809032
--- /dev/null
@@ -0,0 +1,19 @@
+  .option pic2
+
+  .section .text.1,"ax",@progbits
+  .align 4
+  .globl foo1a
+  .type foo1a, @function
+foo1a:
+  nop
+  .globl foo1b
+  .type foo1b, @function
+foo1b:
+  nop
+
+  .section .text.2,"ax",@progbits
+  .align 4
+  .globl foo2
+  .type foo2, @function
+foo2:
+  nop
diff --git a/test/ELF/Inputs/mips-tls.s b/test/ELF/Inputs/mips-tls.s
new file mode 100644 (file)
index 0000000..9e0a098
--- /dev/null
@@ -0,0 +1,5 @@
+ .globl   foo
+ .section .tdata,"awT",%progbits
+ .type    foo, %object
+foo:
+ .word 0
diff --git a/test/ELF/Inputs/no-symtab.o b/test/ELF/Inputs/no-symtab.o
new file mode 100644 (file)
index 0000000..7368ba2
Binary files /dev/null and b/test/ELF/Inputs/no-symtab.o differ
diff --git a/test/ELF/Inputs/plt-aarch64.s b/test/ELF/Inputs/plt-aarch64.s
new file mode 100644 (file)
index 0000000..0f7a4ed
--- /dev/null
@@ -0,0 +1,5 @@
+.global bar
+bar:
+
+.global weak
+weak:
diff --git a/test/ELF/Inputs/ppc64-addr16-error.s b/test/ELF/Inputs/ppc64-addr16-error.s
new file mode 100644 (file)
index 0000000..d83a9f9
--- /dev/null
@@ -0,0 +1,3 @@
+.global sym
+.hidden sym
+sym = 0
diff --git a/test/ELF/Inputs/progname-ver.s b/test/ELF/Inputs/progname-ver.s
new file mode 100644 (file)
index 0000000..06fc294
--- /dev/null
@@ -0,0 +1,3 @@
+.global bar
+bar:
+.quad __progname@GOT
diff --git a/test/ELF/Inputs/protected-shared.s b/test/ELF/Inputs/protected-shared.s
new file mode 100644 (file)
index 0000000..5f4b1da
--- /dev/null
@@ -0,0 +1,10 @@
+        .global foo
+        .protected foo
+foo:
+
+        .global bar
+        .protected bar
+bar:
+
+        .global zed
+zed:
diff --git a/test/ELF/Inputs/relocatable-comdat-multiple.s b/test/ELF/Inputs/relocatable-comdat-multiple.s
new file mode 100644 (file)
index 0000000..837a6bb
--- /dev/null
@@ -0,0 +1,2 @@
+.section .text.c,"axG",@progbits,bbb,comdat
+.section .text.d,"axG",@progbits,bbb,comdat
diff --git a/test/ELF/Inputs/relocatable-ehframe.s b/test/ELF/Inputs/relocatable-ehframe.s
new file mode 100644 (file)
index 0000000..384aac6
--- /dev/null
@@ -0,0 +1,14 @@
+.section foo1,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section bar1,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section dah1,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
diff --git a/test/ELF/Inputs/relocatable-non-alloc.s b/test/ELF/Inputs/relocatable-non-alloc.s
new file mode 100644 (file)
index 0000000..26a9d87
--- /dev/null
@@ -0,0 +1,6 @@
+.section .text.foo,"axG",@progbits,foo,comdat,unique,0
+foo:
+  nop
+
+.section .debug_info
+.long .text.foo
diff --git a/test/ELF/Inputs/relocatable-tls.s b/test/ELF/Inputs/relocatable-tls.s
new file mode 100644 (file)
index 0000000..296beb4
--- /dev/null
@@ -0,0 +1 @@
+callq __tls_get_addr@PLT
diff --git a/test/ELF/Inputs/relocatable.s b/test/ELF/Inputs/relocatable.s
new file mode 100644 (file)
index 0000000..de34a6b
--- /dev/null
@@ -0,0 +1,22 @@
+.text
+.type xx,@object
+.bss
+.globl xx
+.align 4
+xx:
+.long 0
+.size xx, 4
+.type yy,@object
+.globl yy
+.align 4
+yy:
+.long 0
+.size yy, 4
+
+.text
+.globl foo
+.align 16, 0x90
+.type foo,@function
+foo:
+movl $1, xx
+movl $2, yy
diff --git a/test/ELF/Inputs/relocatable2.s b/test/ELF/Inputs/relocatable2.s
new file mode 100644 (file)
index 0000000..93e23bc
--- /dev/null
@@ -0,0 +1,22 @@
+.text
+.type xxx,@object
+.bss
+.globl xxx
+.align 4
+xxx:
+.long 0
+.size xxx, 4
+.type yyy,@object
+.globl yyy
+.align 4
+yyy:
+.long 0
+.size yyy, 4
+
+.text
+.globl bar
+.align 16, 0x90
+.type bar,@function
+bar:
+movl $8, xxx
+movl $9, yyy
diff --git a/test/ELF/Inputs/relocation-copy-alias.s b/test/ELF/Inputs/relocation-copy-alias.s
new file mode 100644 (file)
index 0000000..a9bc3d7
--- /dev/null
@@ -0,0 +1,25 @@
+.data
+
+.globl a1
+.type a1, @object
+.size a1, 1
+a1:
+.weak a2
+.type a2, @object
+.size a2, 1
+a2:
+.byte 1
+
+.weak b1
+.type b1, @object
+.size b1, 1
+b1:
+.weak b2
+.type b2, @object
+.size b2, 1
+b2:
+.globl b3
+.type b3, @object
+.size b3, 1
+b3:
+.byte 1
diff --git a/test/ELF/Inputs/relocation-copy-align-common.s b/test/ELF/Inputs/relocation-copy-align-common.s
new file mode 100644 (file)
index 0000000..b2fc8fd
--- /dev/null
@@ -0,0 +1,7 @@
+.data
+.global foo
+.type foo, @object
+.align 8
+.size foo, 8
+foo:
+.quad 0
diff --git a/test/ELF/Inputs/relocation-copy-align.s b/test/ELF/Inputs/relocation-copy-align.s
new file mode 100644 (file)
index 0000000..83dedc7
--- /dev/null
@@ -0,0 +1,9 @@
+.data
+        .balign 16
+        .zero 12
+
+        .type x,@object
+        .globl x
+x:
+        .long 0
+        .size x, 4
diff --git a/test/ELF/Inputs/relocation-copy-arm.s b/test/ELF/Inputs/relocation-copy-arm.s
new file mode 100644 (file)
index 0000000..ba5ab73
--- /dev/null
@@ -0,0 +1,22 @@
+.bss
+
+.type x,%object
+.globl x
+.balign 16
+x:
+.long 0
+.size x, 4
+
+.type y,%object
+.globl y
+.balign 16
+y:
+.long 0
+.size y, 4
+
+.type z,%object
+.globl z
+.balign 4
+z:
+.long 0
+.size z, 4
diff --git a/test/ELF/Inputs/relocation-copy-relro.s b/test/ELF/Inputs/relocation-copy-relro.s
new file mode 100644 (file)
index 0000000..5f44e0e
--- /dev/null
@@ -0,0 +1,13 @@
+.rodata
+.globl a
+.size a, 4
+.type a, @object
+a:
+.word 1
+
+.section .data.rel.ro,"aw",%progbits
+.globl b
+.size b, 4
+.type b, @object
+b:
+.word 2
diff --git a/test/ELF/Inputs/relocation-copy.s b/test/ELF/Inputs/relocation-copy.s
new file mode 100644 (file)
index 0000000..6b113ab
--- /dev/null
@@ -0,0 +1,22 @@
+.bss
+
+.type x,@object
+.globl x
+.balign 16
+x:
+.long 0
+.size x, 4
+
+.type y,@object
+.globl y
+.balign 16
+y:
+.long 0
+.size y, 4
+
+.type z,@object
+.globl z
+.balign 4
+z:
+.long 0
+.size z, 4
diff --git a/test/ELF/Inputs/relocation-relative-absolute.s b/test/ELF/Inputs/relocation-relative-absolute.s
new file mode 100644 (file)
index 0000000..2341f69
--- /dev/null
@@ -0,0 +1,2 @@
+.globl answer
+answer = 42
diff --git a/test/ELF/Inputs/relocation-size-shared.s b/test/ELF/Inputs/relocation-size-shared.s
new file mode 100644 (file)
index 0000000..02b4cf0
--- /dev/null
@@ -0,0 +1,6 @@
+.data
+.global fooshared
+.type fooshared,%object
+.size fooshared,26
+fooshared:
+.zero 26
diff --git a/test/ELF/Inputs/resolution-end.s b/test/ELF/Inputs/resolution-end.s
new file mode 100644 (file)
index 0000000..6dcc0b7
--- /dev/null
@@ -0,0 +1,3 @@
+.data
+        .quad _end
+        .quad end
diff --git a/test/ELF/Inputs/resolution-shared.s b/test/ELF/Inputs/resolution-shared.s
new file mode 100644 (file)
index 0000000..2f0ccf8
--- /dev/null
@@ -0,0 +1,2 @@
+        .global foo
+foo:
diff --git a/test/ELF/Inputs/resolution.s b/test/ELF/Inputs/resolution.s
new file mode 100644 (file)
index 0000000..70afb16
--- /dev/null
@@ -0,0 +1,107 @@
+local:
+
+.weak RegularWeak_with_RegularWeak
+.size RegularWeak_with_RegularWeak, 32
+RegularWeak_with_RegularWeak:
+
+.global RegularWeak_with_RegularStrong
+.size RegularWeak_with_RegularStrong, 33
+RegularWeak_with_RegularStrong:
+
+.weak RegularStrong_with_RegularWeak
+.size RegularStrong_with_RegularWeak, 34
+RegularStrong_with_RegularWeak:
+
+.weak RegularWeak_with_UndefWeak
+.size RegularWeak_with_UndefWeak, 35
+.quad RegularWeak_with_UndefWeak
+
+.size RegularWeak_with_UndefStrong, 36
+.quad RegularWeak_with_UndefStrong
+
+.weak RegularStrong_with_UndefWeak
+.size RegularStrong_with_UndefWeak, 37
+.quad RegularStrong_with_UndefWeak
+
+.size RegularStrong_with_UndefStrong, 38
+.quad RegularStrong_with_UndefStrong
+
+.weak RegularWeak_with_CommonWeak
+.comm RegularWeak_with_CommonWeak,39,4
+
+.comm RegularWeak_with_CommonStrong,40,4
+
+.weak RegularStrong_with_CommonWeak
+.comm RegularStrong_with_CommonWeak,41,4
+
+.comm RegularStrong_with_CommonStrong,42,4
+
+.weak UndefWeak_with_RegularWeak
+.size UndefWeak_with_RegularWeak, 43
+UndefWeak_with_RegularWeak:
+
+.global UndefWeak_with_RegularStrong
+.size UndefWeak_with_RegularStrong, 44
+UndefWeak_with_RegularStrong:
+
+.weak UndefStrong_with_RegularWeak
+.size UndefStrong_with_RegularWeak, 45
+UndefStrong_with_RegularWeak:
+
+.global UndefStrong_with_RegularStrong
+.size UndefStrong_with_RegularStrong, 46
+UndefStrong_with_RegularStrong:
+
+.weak UndefWeak_with_UndefWeak
+.size UndefWeak_with_UndefWeak, 47
+.quad UndefWeak_with_UndefWeak
+
+.weak UndefWeak_with_CommonWeak
+.comm UndefWeak_with_CommonWeak,48,4
+
+.comm UndefWeak_with_CommonStrong,49,4
+
+.weak UndefStrong_with_CommonWeak
+.comm UndefStrong_with_CommonWeak,50,4
+
+.comm UndefStrong_with_CommonStrong,51,4
+
+.weak CommonWeak_with_RegularWeak
+.size CommonWeak_with_RegularWeak, 52
+CommonWeak_with_RegularWeak:
+
+.global CommonWeak_with_RegularStrong
+.size CommonWeak_with_RegularStrong, 53
+CommonWeak_with_RegularStrong:
+
+.weak CommonStrong_with_RegularWeak
+.size CommonStrong_with_RegularWeak, 54
+CommonStrong_with_RegularWeak:
+
+.global CommonStrong_with_RegularStrong
+.size CommonStrong_with_RegularStrong, 55
+CommonStrong_with_RegularStrong:
+
+.weak CommonWeak_with_UndefWeak
+.size CommonWeak_with_UndefWeak, 56
+.quad CommonWeak_with_UndefWeak
+
+.size CommonWeak_with_UndefStrong, 57
+.quad CommonWeak_with_UndefStrong
+
+.weak CommonStrong_with_UndefWeak
+.size CommonStrong_with_UndefWeak, 58
+.quad CommonStrong_with_UndefWeak
+
+.size CommonStrong_with_UndefStrong, 59
+.quad CommonStrong_with_UndefStrong
+
+.weak CommonWeak_with_CommonWeak
+.comm CommonWeak_with_CommonWeak,60,4
+
+.comm CommonWeak_with_CommonStrong,61,4
+
+.weak CommonStrong_with_CommonWeak
+.comm CommonStrong_with_CommonWeak,62,4
+
+.comm CommonStrong_with_CommonStrong,63,4
diff --git a/test/ELF/Inputs/rodynamic.s b/test/ELF/Inputs/rodynamic.s
new file mode 100644 (file)
index 0000000..a06f4be
--- /dev/null
@@ -0,0 +1,4 @@
+.global foo
+.type foo, @function
+foo:
+  ret
diff --git a/test/ELF/Inputs/shared-ppc64.s b/test/ELF/Inputs/shared-ppc64.s
new file mode 100644 (file)
index 0000000..b0117ac
--- /dev/null
@@ -0,0 +1,9 @@
+.section        ".opd","aw"
+.global bar
+bar:
+.quad   .Lbar,.TOC.@tocbase,0
+.quad   .Lbar,0,0
+
+.text
+.Lbar:
+        blr
diff --git a/test/ELF/Inputs/shared.s b/test/ELF/Inputs/shared.s
new file mode 100644 (file)
index 0000000..c3c22fe
--- /dev/null
@@ -0,0 +1,10 @@
+.global bar
+.type bar, @function
+bar:
+
+.global bar2
+.type bar2, @function
+bar2:
+
+.global zed
+zed:
diff --git a/test/ELF/Inputs/shared2-x86-64.s b/test/ELF/Inputs/shared2-x86-64.s
new file mode 100644 (file)
index 0000000..925e6a4
--- /dev/null
@@ -0,0 +1,9 @@
+.global bar2
+.type bar2, @function
+bar2:
+ ret
+
+.global zed2
+.type  zed2, @function
+zed2:
+ ret
diff --git a/test/ELF/Inputs/shared2.s b/test/ELF/Inputs/shared2.s
new file mode 100644 (file)
index 0000000..a723902
--- /dev/null
@@ -0,0 +1,6 @@
+.global bar2
+.type bar2, @function
+bar2:
+
+.global zed2
+zed2:
diff --git a/test/ELF/Inputs/shared3.s b/test/ELF/Inputs/shared3.s
new file mode 100644 (file)
index 0000000..d1f6ffe
--- /dev/null
@@ -0,0 +1,3 @@
+.global baz
+.type barz, @function
+baz:
diff --git a/test/ELF/Inputs/shf-info-link.test b/test/ELF/Inputs/shf-info-link.test
new file mode 100644 (file)
index 0000000..b877969
--- /dev/null
@@ -0,0 +1,21 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          foo
+        Type:            R_X86_64_64
+Symbols:
+  Global:
+    - Name:            foo
diff --git a/test/ELF/Inputs/sht-group-gold-r.elf b/test/ELF/Inputs/sht-group-gold-r.elf
new file mode 100644 (file)
index 0000000..d2309c9
Binary files /dev/null and b/test/ELF/Inputs/sht-group-gold-r.elf differ
diff --git a/test/ELF/Inputs/sht-group-gold-r.s b/test/ELF/Inputs/sht-group-gold-r.s
new file mode 100644 (file)
index 0000000..aca262d
--- /dev/null
@@ -0,0 +1,14 @@
+# sht-group-gold-r.elf is produced by
+#
+#   llvm-mc -filetype=obj -triple=x86_64-pc-linux sht-group-gold-r.s -o sht-group-gold-r.o
+#   ld.gold -o sht-group-gold-r.elf -r sht-group-gold-r.o
+
+.global foo, bar
+
+.section .text.foo,"aG",@progbits,group_foo,comdat
+foo:
+  nop
+
+.section .text.bar,"aG",@progbits,group_bar,comdat
+bar:
+  nop
diff --git a/test/ELF/Inputs/start-lib-comdat.s b/test/ELF/Inputs/start-lib-comdat.s
new file mode 100644 (file)
index 0000000..dcbaaf4
--- /dev/null
@@ -0,0 +1,5 @@
+        .global bar
+bar:
+        .section        .sec,"aG",@progbits,zed,comdat
+        .global zed
+zed:
diff --git a/test/ELF/Inputs/start-lib1.s b/test/ELF/Inputs/start-lib1.s
new file mode 100644 (file)
index 0000000..d401b20
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+  call bar
diff --git a/test/ELF/Inputs/start-lib2.s b/test/ELF/Inputs/start-lib2.s
new file mode 100644 (file)
index 0000000..f500936
--- /dev/null
@@ -0,0 +1,2 @@
+.globl bar
+bar:
diff --git a/test/ELF/Inputs/startstop-shared2.s b/test/ELF/Inputs/startstop-shared2.s
new file mode 100644 (file)
index 0000000..414bf6d
--- /dev/null
@@ -0,0 +1,2 @@
+.globl __start_foo
+__start_foo:
diff --git a/test/ELF/Inputs/symbol-override.s b/test/ELF/Inputs/symbol-override.s
new file mode 100644 (file)
index 0000000..ab3bf8d
--- /dev/null
@@ -0,0 +1,16 @@
+.text
+.globl foo
+.type foo,@function
+foo:
+nop
+
+.globl bar
+.type bar,@function
+bar:
+nop
+
+.globl do
+.type do,@function
+do:
+callq foo@PLT
+callq bar@PLT
diff --git a/test/ELF/Inputs/symver-archive1.s b/test/ELF/Inputs/symver-archive1.s
new file mode 100644 (file)
index 0000000..be7c644
--- /dev/null
@@ -0,0 +1,6 @@
+.text
+.globl x
+.type x, @function
+x:
+
+.symver x, xx@@VER
diff --git a/test/ELF/Inputs/symver-archive2.s b/test/ELF/Inputs/symver-archive2.s
new file mode 100644 (file)
index 0000000..a9b9d0b
--- /dev/null
@@ -0,0 +1 @@
+call xx@PLT
diff --git a/test/ELF/Inputs/tls-got-entry.s b/test/ELF/Inputs/tls-got-entry.s
new file mode 100644 (file)
index 0000000..e1e09a3
--- /dev/null
@@ -0,0 +1,13 @@
+.globl __tls_get_addr
+.align 16, 0x90
+.type __tls_get_addr,@function
+__tls_get_addr:
+
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
diff --git a/test/ELF/Inputs/tls-got.s b/test/ELF/Inputs/tls-got.s
new file mode 100644 (file)
index 0000000..5681d00
--- /dev/null
@@ -0,0 +1,14 @@
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
diff --git a/test/ELF/Inputs/tls-in-archive.s b/test/ELF/Inputs/tls-in-archive.s
new file mode 100644 (file)
index 0000000..0474a41
--- /dev/null
@@ -0,0 +1,3 @@
+        .type foo, @tls_object
+        .globl  foo
+foo:
diff --git a/test/ELF/Inputs/tls-mismatch.s b/test/ELF/Inputs/tls-mismatch.s
new file mode 100644 (file)
index 0000000..8c14f58
--- /dev/null
@@ -0,0 +1,4 @@
+.tbss
+.globl tlsvar
+tlsvar:
+  .space 4
diff --git a/test/ELF/Inputs/tls-opt-gdie.s b/test/ELF/Inputs/tls-opt-gdie.s
new file mode 100644 (file)
index 0000000..361578f
--- /dev/null
@@ -0,0 +1,20 @@
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
+.type  tlsshared1,@object
+.globl tlsshared1
+.align 4
+tlsshared1:
+ .long 0
+ .size tlsshared1, 4
+
+.text
+.globl __tls_get_addr
+.align 16, 0x90
+.type __tls_get_addr,@function
+__tls_get_addr:
diff --git a/test/ELF/Inputs/tls-opt-gdiele-i686.s b/test/ELF/Inputs/tls-opt-gdiele-i686.s
new file mode 100644 (file)
index 0000000..ab72b9d
--- /dev/null
@@ -0,0 +1,20 @@
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
+.type  tlsshared1,@object
+.globl tlsshared1
+.align 4
+tlsshared1:
+ .long 0
+ .size tlsshared1, 4
+
+.text
+ .globl __tls_get_addr
+ .align 16, 0x90
+ .type __tls_get_addr,@function
+__tls_get_addr:
diff --git a/test/ELF/Inputs/tls-opt-iele-i686-nopic.s b/test/ELF/Inputs/tls-opt-iele-i686-nopic.s
new file mode 100644 (file)
index 0000000..a090065
--- /dev/null
@@ -0,0 +1,15 @@
+.type tlsshared0,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared0
+.align 4
+tlsshared0:
+ .long 0
+ .size tlsshared0, 4
+
+.type tlsshared1,@object
+.section .tbss,"awT",@nobits
+.globl tlsshared1
+.align 4
+tlsshared1:
+ .long 0
+ .size tlsshared1, 4
diff --git a/test/ELF/Inputs/trace-ar1.s b/test/ELF/Inputs/trace-ar1.s
new file mode 100644 (file)
index 0000000..0292bae
--- /dev/null
@@ -0,0 +1,2 @@
+.globl _used
+_used:
diff --git a/test/ELF/Inputs/trace-ar2.s b/test/ELF/Inputs/trace-ar2.s
new file mode 100644 (file)
index 0000000..d56f304
--- /dev/null
@@ -0,0 +1,2 @@
+.globl _notused
+_notused:
diff --git a/test/ELF/Inputs/trace-symbols-foo-strong.s b/test/ELF/Inputs/trace-symbols-foo-strong.s
new file mode 100644 (file)
index 0000000..8746429
--- /dev/null
@@ -0,0 +1,14 @@
+.text
+.globl foo
+.type  foo, @function
+foo:
+nop
+
+.globl bar
+.type  bar, @function
+bar:
+nop
+
+.global func2
+.type   func2, @function
+func2:
diff --git a/test/ELF/Inputs/trace-symbols-foo-weak.s b/test/ELF/Inputs/trace-symbols-foo-weak.s
new file mode 100644 (file)
index 0000000..d071ebe
--- /dev/null
@@ -0,0 +1,12 @@
+.comm  common,4,4
+.text
+.weak  foo
+.type  foo, @function
+foo:
+callq bar@PLT
+
+.globl  func1
+.type   func1, @function
+func1:
+call func2@PLT
+
diff --git a/test/ELF/Inputs/uabs_label.s b/test/ELF/Inputs/uabs_label.s
new file mode 100644 (file)
index 0000000..b2a6721
--- /dev/null
@@ -0,0 +1,4 @@
+# Sample label to test R_AARCH64_MOVW_UABS relocations
+
+.globl uabs_label
+uabs_label = 0xF000E000D000C
diff --git a/test/ELF/Inputs/undef-debug.s b/test/ELF/Inputs/undef-debug.s
new file mode 100644 (file)
index 0000000..db8aaf1
--- /dev/null
@@ -0,0 +1,11 @@
+.file 1 "dir/undef-debug.s"
+.loc 1 3
+        .quad zed3
+
+.section .text.1,"ax"
+.loc 1 7
+        .quad zed4
+
+.section .text.2,"ax"
+.loc 1 11
+        .quad zed5
diff --git a/test/ELF/Inputs/undef-with-plt-addr.s b/test/ELF/Inputs/undef-with-plt-addr.s
new file mode 100644 (file)
index 0000000..b12737d
--- /dev/null
@@ -0,0 +1,7 @@
+       .globl  set_data
+       .type   set_data,@function
+set_data:
+
+        .globl  foo
+        .type   foo,@function
+foo:
diff --git a/test/ELF/Inputs/undef.s b/test/ELF/Inputs/undef.s
new file mode 100644 (file)
index 0000000..01776bf
--- /dev/null
@@ -0,0 +1,3 @@
+        .global zed1
+zed1:
+        .quad zed2
diff --git a/test/ELF/Inputs/unknown-reloc.s b/test/ELF/Inputs/unknown-reloc.s
new file mode 100644 (file)
index 0000000..370ba33
--- /dev/null
@@ -0,0 +1,2 @@
+.global und
+und:
diff --git a/test/ELF/Inputs/unresolved-symbols.s b/test/ELF/Inputs/unresolved-symbols.s
new file mode 100644 (file)
index 0000000..b504708
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _shared
+_shared:
+  callq undef@PLT
diff --git a/test/ELF/Inputs/use-bar.s b/test/ELF/Inputs/use-bar.s
new file mode 100644 (file)
index 0000000..cc82b6f
--- /dev/null
@@ -0,0 +1,2 @@
+.section .bar,"a"
+ .quad _bar
diff --git a/test/ELF/Inputs/verdef-defaultver.s b/test/ELF/Inputs/verdef-defaultver.s
new file mode 100644 (file)
index 0000000..6664d62
--- /dev/null
@@ -0,0 +1,22 @@
+b@V1 = b_1
+b@@V2 = b_2
+
+.globl a
+.type  a,@function
+a:
+retq
+
+.globl b_1
+.type  b_1,@function
+b_1:
+retq
+
+.globl b_2
+.type  b_2,@function
+b_2:
+retq
+
+.globl c
+.type  c,@function
+c:
+retq
diff --git a/test/ELF/Inputs/verdef.s b/test/ELF/Inputs/verdef.s
new file mode 100644 (file)
index 0000000..349d5fd
--- /dev/null
@@ -0,0 +1,6 @@
+.text
+.globl _start
+_start:
+ callq a
+ callq b
+ callq c
diff --git a/test/ELF/Inputs/verneed.so.sh b/test/ELF/Inputs/verneed.so.sh
new file mode 100755 (executable)
index 0000000..3423f67
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh -eu
+
+# This script was used to produce the verneed{1,2}.so files.
+
+tmp=$(mktemp -d)
+
+echo "v1 {}; v2 {}; v3 {}; { local: *; };" > $tmp/verneed.script
+
+cat > $tmp/verneed1.s <<eof
+.globl f1_v1
+f1_v1:
+ret
+
+.globl f1_v2
+f1_v2:
+ret
+
+.globl f1_v3
+f1_v3:
+ret
+
+.symver f1_v1, f1@v1
+.symver f1_v2, f1@v2
+.symver f1_v3, f1@@v3
+
+.globl f2_v1
+f2_v1:
+ret
+
+.globl f2_v2
+f2_v2:
+ret
+
+.symver f2_v1, f2@v1
+.symver f2_v2, f2@@v2
+
+.globl f3_v1
+f3_v1:
+ret
+
+.symver f3_v1, f3@v1
+eof
+
+as -o $tmp/verneed1.o $tmp/verneed1.s
+ld.gold -shared -o verneed1.so $tmp/verneed1.o --version-script $tmp/verneed.script -soname verneed1.so.0
+
+cat > $tmp/verneed2.s <<eof
+.globl g1_v1
+g1_v1:
+ret
+
+.symver g1_v1, g1@@v1
+eof
+
+as -o $tmp/verneed2.o $tmp/verneed2.s
+ld.gold -shared -o verneed2.so $tmp/verneed2.o --version-script $tmp/verneed.script -soname verneed2.so.0
+
+rm -rf $tmp
diff --git a/test/ELF/Inputs/verneed1.so b/test/ELF/Inputs/verneed1.so
new file mode 100755 (executable)
index 0000000..744852b
Binary files /dev/null and b/test/ELF/Inputs/verneed1.so differ
diff --git a/test/ELF/Inputs/verneed2.so b/test/ELF/Inputs/verneed2.so
new file mode 100755 (executable)
index 0000000..ba6c05e
Binary files /dev/null and b/test/ELF/Inputs/verneed2.so differ
diff --git a/test/ELF/Inputs/version-script-err.script b/test/ELF/Inputs/version-script-err.script
new file mode 100644 (file)
index 0000000..37de598
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  global:
+   foo
+};
diff --git a/test/ELF/Inputs/version-script-no-warn2.s b/test/ELF/Inputs/version-script-no-warn2.s
new file mode 100644 (file)
index 0000000..59de9d4
--- /dev/null
@@ -0,0 +1 @@
+call foo@plt
diff --git a/test/ELF/Inputs/version-script-weak.s b/test/ELF/Inputs/version-script-weak.s
new file mode 100644 (file)
index 0000000..09f5cf0
--- /dev/null
@@ -0,0 +1,4 @@
+.text
+.globl foo
+.type foo,@function
+foo:
diff --git a/test/ELF/Inputs/version-undef-sym.so b/test/ELF/Inputs/version-undef-sym.so
new file mode 100755 (executable)
index 0000000..abb4399
Binary files /dev/null and b/test/ELF/Inputs/version-undef-sym.so differ
diff --git a/test/ELF/Inputs/version-use.script b/test/ELF/Inputs/version-use.script
new file mode 100644 (file)
index 0000000..5b2721b
--- /dev/null
@@ -0,0 +1,6 @@
+ABC {
+global:
+foo;
+local:
+*;
+};
diff --git a/test/ELF/Inputs/version-use.so b/test/ELF/Inputs/version-use.so
new file mode 100755 (executable)
index 0000000..153544e
Binary files /dev/null and b/test/ELF/Inputs/version-use.so differ
diff --git a/test/ELF/Inputs/visibility.s b/test/ELF/Inputs/visibility.s
new file mode 100644 (file)
index 0000000..fe7cd9a
--- /dev/null
@@ -0,0 +1,14 @@
+.data
+.quad default
+
+.protected protected
+.quad protected
+
+.hidden hidden
+.quad hidden
+
+.internal internal
+.quad internal
+
+.hidden protected_with_hidden
+.quad protected_with_hidden
diff --git a/test/ELF/Inputs/warn-common.s b/test/ELF/Inputs/warn-common.s
new file mode 100644 (file)
index 0000000..fc4509b
--- /dev/null
@@ -0,0 +1,2 @@
+.type arr,@object
+.comm arr,8,4
diff --git a/test/ELF/Inputs/warn-common2.s b/test/ELF/Inputs/warn-common2.s
new file mode 100644 (file)
index 0000000..976c5be
--- /dev/null
@@ -0,0 +1,8 @@
+.type arr,@object
+.data
+.globl arr
+.p2align 2
+arr:
+ .long 1
+ .long 0
+ .size arr, 8
diff --git a/test/ELF/Inputs/weak-and-strong-undef.s b/test/ELF/Inputs/weak-and-strong-undef.s
new file mode 100644 (file)
index 0000000..a5e476d
--- /dev/null
@@ -0,0 +1 @@
+        .weak foo
diff --git a/test/ELF/Inputs/whole-archive.s b/test/ELF/Inputs/whole-archive.s
new file mode 100644 (file)
index 0000000..816b24e
--- /dev/null
@@ -0,0 +1,2 @@
+.globl _bar
+_bar:
diff --git a/test/ELF/Inputs/wrap-dynamic-undef.s b/test/ELF/Inputs/wrap-dynamic-undef.s
new file mode 100644 (file)
index 0000000..ade7955
--- /dev/null
@@ -0,0 +1,2 @@
+.global foo
+foo:
diff --git a/test/ELF/Inputs/wrap.s b/test/ELF/Inputs/wrap.s
new file mode 100644 (file)
index 0000000..584e270
--- /dev/null
@@ -0,0 +1,4 @@
+.globl foo, __wrap_foo, __real_foo
+foo = 0x11000
+__wrap_foo = 0x11010
+__real_foo = 0x11020
diff --git a/test/ELF/Inputs/x86-64-relax-offset.s b/test/ELF/Inputs/x86-64-relax-offset.s
new file mode 100644 (file)
index 0000000..780d1d0
--- /dev/null
@@ -0,0 +1,7 @@
+.global foo
+.hidden foo
+foo:
+        nop
+        nop
+        nop
+        nop
diff --git a/test/ELF/Inputs/x86-64-reloc-16-error.s b/test/ELF/Inputs/x86-64-reloc-16-error.s
new file mode 100644 (file)
index 0000000..8deed64
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 65536
diff --git a/test/ELF/Inputs/x86-64-reloc-16.s b/test/ELF/Inputs/x86-64-reloc-16.s
new file mode 100644 (file)
index 0000000..c5b2f55
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 0x42
diff --git a/test/ELF/Inputs/x86-64-reloc-8-error.s b/test/ELF/Inputs/x86-64-reloc-8-error.s
new file mode 100644 (file)
index 0000000..b6a7626
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 256
diff --git a/test/ELF/Inputs/x86-64-reloc-8.s b/test/ELF/Inputs/x86-64-reloc-8.s
new file mode 100644 (file)
index 0000000..c5b2f55
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+.hidden foo
+foo = 0x42
diff --git a/test/ELF/Inputs/x86-64-reloc-error.s b/test/ELF/Inputs/x86-64-reloc-error.s
new file mode 100644 (file)
index 0000000..bce6f8f
--- /dev/null
@@ -0,0 +1,7 @@
+.global big
+.hidden big
+big = 0x1000000000
+
+.global foo
+.hidden foo
+foo = 0
diff --git a/test/ELF/Inputs/x86-64-tls-gd-got.s b/test/ELF/Inputs/x86-64-tls-gd-got.s
new file mode 100644 (file)
index 0000000..67a021a
--- /dev/null
@@ -0,0 +1,6 @@
+        .globl  bar
+        .section        .tdata,"awT",@progbits
+        .align 4
+        .type   bar, @object
+bar:
+        .long   42
diff --git a/test/ELF/Inputs/ztext-text-notext.s b/test/ELF/Inputs/ztext-text-notext.s
new file mode 100644 (file)
index 0000000..f66b3ee
--- /dev/null
@@ -0,0 +1,10 @@
+        .global bar
+        .type bar, @object
+        .size bar, 8
+bar:
+        .quad 0
+
+        .global zed
+        .type zed, @function
+zed:
+        nop
diff --git a/test/ELF/aarch64-abs16.s b/test/ELF/aarch64-abs16.s
new file mode 100644 (file)
index 0000000..c4f5b3e
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .hword foo + 0xfeff
+  .hword foo - 0x8100
+
+// RUN: ld.lld %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 11000: S = 0x100, A = 0xfeff
+//        S + A = 0xffff
+// 11002: S = 0x100, A = -0x8100
+//        S + A = 0x8000
+// CHECK-NEXT: 20000 ffff0080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_ABS16 out of range
diff --git a/test/ELF/aarch64-abs32.s b/test/ELF/aarch64-abs32.s
new file mode 100644 (file)
index 0000000..b051692
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .word foo + 0xfffffeff
+  .word foo - 0x80000100
+
+// RUN: ld.lld %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 20000: S = 0x100, A = 0xfffffeff
+//        S + A = 0xffffffff
+// 20004: S = 0x100, A = -0x80000100
+//        S + A = 0x80000000
+// CHECK-NEXT: 20000 ffffffff 00000080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_ABS32 out of range
diff --git a/test/ELF/aarch64-abs64-dyn.s b/test/ELF/aarch64-abs64-dyn.s
new file mode 100644 (file)
index 0000000..2220225
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
+
+// Creates a R_AARCH64_ABS64 relocation against foo and bar
+        .globl foo
+foo:
+
+        .global bar
+        .hidden bar
+bar:
+
+        .data
+        .xword foo
+        .xword bar
+
+// RUN: ld.lld -shared -o %t.so %t.o
+// RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s
+
+// CHECK:      Dynamic Relocations {
+// CHECK-NEXT:   {{.*}} R_AARCH64_RELATIVE - [[BAR_ADDR:.*]]
+// CHECK-NEXT:   {{.*}} R_AARCH64_ABS64 foo 0x0
+// CHECK-NEXT: }
+
+// CHECK:      Symbols [
+// CHECK:        Symbol {
+// CHECK:          Name: bar
+// CHECK-NEXT:     Value: [[BAR_ADDR]]
diff --git a/test/ELF/aarch64-call26-error.s b/test/ELF/aarch64-call26-error.s
new file mode 100644 (file)
index 0000000..4b666c6
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %t %tabs -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.text
+.globl _start
+_start:
+    bl big
+
+// CHECK: R_AARCH64_CALL26 out of range
diff --git a/test/ELF/aarch64-condb-reloc.s b/test/ELF/aarch64-condb-reloc.s
new file mode 100644 (file)
index 0000000..23c16c2
--- /dev/null
@@ -0,0 +1,99 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-condb-reloc.s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld -shared %t1 %t2 -o %t3
+# RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s
+# RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+# REQUIRES: aarch64
+
+# 0x11024 - 36 = 0x11000
+# 0x11028 - 24 = 0x11010
+# 0x1102c - 16 = 0x1101c
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: _foo:
+# CHECK-NEXT:    20000: {{.*}} nop
+# CHECK-NEXT:    20004: {{.*}} nop
+# CHECK-NEXT:    20008: {{.*}} nop
+# CHECK-NEXT:    2000c: {{.*}} nop
+# CHECK:      _bar:
+# CHECK-NEXT:    20010: {{.*}} nop
+# CHECK-NEXT:    20014: {{.*}} nop
+# CHECK-NEXT:    20018: {{.*}} nop
+# CHECK:      _dah:
+# CHECK-NEXT:    2001c: {{.*}} nop
+# CHECK-NEXT:    20020: {{.*}} nop
+# CHECK:      _start:
+# CHECK-NEXT:    20024: {{.*}} b.eq #-36
+# CHECK-NEXT:    20028: {{.*}} b.eq #-24
+# CHECK-NEXT:    2002c: {{.*}} b.eq #-16
+
+#DSOREL:      Section {
+#DSOREL:        Index:
+#DSOREL:        Name: .got.plt
+#DSOREL-NEXT:   Type: SHT_PROGBITS
+#DSOREL-NEXT:   Flags [
+#DSOREL-NEXT:     SHF_ALLOC
+#DSOREL-NEXT:     SHF_WRITE
+#DSOREL-NEXT:   ]
+#DSOREL-NEXT:   Address: 0x20000
+#DSOREL-NEXT:   Offset: 0x20000
+#DSOREL-NEXT:   Size: 48
+#DSOREL-NEXT:   Link: 0
+#DSOREL-NEXT:   Info: 0
+#DSOREL-NEXT:   AddressAlignment: 8
+#DSOREL-NEXT:   EntrySize: 0
+#DSOREL-NEXT:  }
+#DSOREL:      Relocations [
+#DSOREL-NEXT:  Section ({{.*}}) .rela.plt {
+#DSOREL-NEXT:    0x20018 R_AARCH64_JUMP_SLOT _foo
+#DSOREL-NEXT:    0x20020 R_AARCH64_JUMP_SLOT _bar
+#DSOREL-NEXT:    0x20028 R_AARCH64_JUMP_SLOT _dah
+#DSOREL-NEXT:  }
+#DSOREL-NEXT:]
+
+#DSO:      Disassembly of section .text:
+#DSO-NEXT: _foo:
+#DSO-NEXT:     10000: {{.*}} nop
+#DSO-NEXT:     10004: {{.*}} nop
+#DSO-NEXT:     10008: {{.*}} nop
+#DSO-NEXT:     1000c: {{.*}} nop
+#DSO:      _bar:
+#DSO-NEXT:     10010: {{.*}} nop
+#DSO-NEXT:     10014: {{.*}} nop
+#DSO-NEXT:     10018: {{.*}} nop
+#DSO:      _dah:
+#DSO-NEXT:     1001c: {{.*}} nop
+#DSO-NEXT:     10020: {{.*}} nop
+#DSO:      _start:
+#DSO-NEXT:     10024: {{.*}} b.eq #44
+#DSO-NEXT:     10028: {{.*}} b.eq #56
+#DSO-NEXT:     1002c: {{.*}} b.eq #68
+#DSO-NEXT: Disassembly of section .plt:
+#DSO-NEXT: .plt:
+#DSO-NEXT:     10030: {{.*}} stp x16, x30, [sp, #-16]!
+#DSO-NEXT:     10034: {{.*}} adrp x16, #65536
+#DSO-NEXT:     10038: {{.*}} ldr x17, [x16, #16]
+#DSO-NEXT:     1003c: {{.*}} add x16, x16, #16
+#DSO-NEXT:     10040: {{.*}} br x17
+#DSO-NEXT:     10044: {{.*}} nop
+#DSO-NEXT:     10048: {{.*}} nop
+#DSO-NEXT:     1004c: {{.*}} nop
+#DSO-NEXT:     10050: {{.*}} adrp x16, #65536
+#DSO-NEXT:     10054: {{.*}} ldr x17, [x16, #24]
+#DSO-NEXT:     10058: {{.*}} add x16, x16, #24
+#DSO-NEXT:     1005c: {{.*}} br x17
+#DSO-NEXT:     10060: {{.*}} adrp x16, #65536
+#DSO-NEXT:     10064: {{.*}} ldr x17, [x16, #32]
+#DSO-NEXT:     10068: {{.*}} add x16, x16, #32
+#DSO-NEXT:     1006c: {{.*}} br x17
+#DSO-NEXT:     10070: {{.*}} adrp x16, #65536
+#DSO-NEXT:     10074: {{.*}} ldr x17, [x16, #40]
+#DSO-NEXT:     10078: {{.*}} add x16, x16, #40
+#DSO-NEXT:     1007c: {{.*}} br x17
+
+.globl _start
+_start:
+ b.eq _foo
+ b.eq _bar
+ b.eq _dah
diff --git a/test/ELF/aarch64-copy.s b/test/ELF/aarch64-copy.s
new file mode 100644 (file)
index 0000000..ffecf2f
--- /dev/null
@@ -0,0 +1,93 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s
+// RUN: llvm-objdump -s -section=.rodata %t3 | FileCheck -check-prefix=RODATA %s
+
+.text
+.globl _start
+_start:
+    adr x1, x
+    adrp x2, y
+    add x2, x2, :lo12:y
+.rodata
+    .word z
+
+// CHECK:     Name: .bss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x40000
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 24
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment: 16
+
+// CHECK: Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x40000
+// CHECK-NEXT:       Type: R_AARCH64_COPY
+// CHECK-NEXT:       Symbol: x
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x40010
+// CHECK-NEXT:       Type: R_AARCH64_COPY
+// CHECK-NEXT:       Symbol: y
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x40014
+// CHECK-NEXT:       Type: R_AARCH64_COPY
+// CHECK-NEXT:       Symbol: z
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: Symbols [
+// CHECK:     Name: x
+// CHECK-NEXT:     Value: 0x40000
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .bss
+// CHECK:     Name: y
+// CHECK-NEXT:     Value: 0x40010
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .bss
+// CHECK:     Name: z
+// CHECK-NEXT:     Value: 0x40014
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .bss
+// CHECK: ]
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// S(x) = 0x40000, A = 0, P = 0x20000
+// S + A - P = 0x20000 = 131072
+// CODE-NEXT:  20000: {{.*}} adr  x1, #131072
+// S(y) = 0x40010, A = 0, P = 0x20004
+// Page(S + A) - Page(P) = 0x40000 - 0x20000 = 0x20000 = 131072
+// CODE-NEXT:  20004: {{.*}} adrp x2, #131072
+// S(y) = 0x40010, A = 0
+// (S + A) & 0xFFF = 0x10 = 16
+// CODE-NEXT:  20008: {{.*}} add  x2, x2, #16
+
+// RODATA: Contents of section .rodata:
+// S(z) = 0x40014
+// RODATA-NEXT:  101c8 14000400
diff --git a/test/ELF/aarch64-copy2.s b/test/ELF/aarch64-copy2.s
new file mode 100644 (file)
index 0000000..6f72e21
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: llvm-mc %p/Inputs/aarch64-copy2.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -t %t | FileCheck %s
+
+        .global _start
+_start:
+        adrp    x8, foo
+        bl bar
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x20030
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
diff --git a/test/ELF/aarch64-data-relocs.s b/test/ELF/aarch64-data-relocs.s
new file mode 100644 (file)
index 0000000..19e11bc
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: ld.lld %t %t256.o -o %t2
+// RUN: llvm-objdump -s %t2 | FileCheck %s
+// REQUIRES: aarch64
+
+.globl _start
+_start:
+.section .R_AARCH64_ABS64, "ax",@progbits
+  .xword foo + 0x24
+
+// S = 0x100, A = 0x24
+// S + A = 0x124
+// CHECK: Contents of section .R_AARCH64_ABS64:
+// CHECK-NEXT: 20000 24010000 00000000
+
+.section .R_AARCH64_PREL64, "ax",@progbits
+  .xword foo - . + 0x24
+
+// S = 0x100, A = 0x24, P = 0x20008
+// S + A - P = 0xfffffffffffe011c
+// CHECK: Contents of section .R_AARCH64_PREL64:
+// CHECK-NEXT: 20008 1c01feff ffffffff
diff --git a/test/ELF/aarch64-fpic-abs16.s b/test/ELF/aarch64-fpic-abs16.s
new file mode 100644 (file)
index 0000000..2b14b11
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK:      relocation R_AARCH64_ABS16 cannot be used against shared object; recompile with -fPIC
+// CHECK-NEXT: >>> defined in {{.*}}.o
+// CHECK-NEXT: >>> referenced by {{.*}}.o:(.data+0x0)
+
+.data
+  .hword foo
diff --git a/test/ELF/aarch64-fpic-add_abs_lo12_nc.s b/test/ELF/aarch64-fpic-add_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..9e13fd1
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_ADD_ABS_LO12_NC against symbol: dat
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+  add x0, x0, :lo12:dat
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-adr_prel_lo21.s b/test/ELF/aarch64-fpic-adr_prel_lo21.s
new file mode 100644 (file)
index 0000000..c1e6bc6
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_ADR_PREL_LO21 against symbol: dat
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+  adr x0, dat
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s b/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s
new file mode 100644 (file)
index 0000000..e27867b
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol: dat
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+  adrp x0, dat
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-got.s b/test/ELF/aarch64-fpic-got.s
new file mode 100644 (file)
index 0000000..70b2a7a
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o %t-lib.o
+# RUN: ld.lld -shared %t-lib.o -o %t-lib.so
+# RUN: ld.lld %t-lib.so %t.o -o %t.exe
+# RUN: llvm-readobj -dyn-relocations %t.exe | FileCheck %s
+
+## Checks if got access to dynamic objects is done through a got relative
+## dynamic relocation and not using plt relative (R_AARCH64_JUMP_SLOT).
+# CHECK:       Dynamic Relocations {
+# CHECK-NEXT:    0x{{[0-9A-F]+}}  R_AARCH64_GLOB_DAT bar 0x0
+# CHECK-NEXT:  }
+
+.globl _start
+_start:
+  adrp x0, :got:bar
+  ldr  x0, [x0, :got_lo12:bar]
diff --git a/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..02b75a5
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST32_ABS_LO12_NC against symbol: dat
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+  ldr s4, [x0, :lo12:dat]
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..45e4f20
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST64_ABS_LO12_NC against symbol: dat
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+  ldr x0, [x0, :lo12:dat]
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s
new file mode 100644 (file)
index 0000000..16e7df1
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: can't create dynamic relocation R_AARCH64_LDST8_ABS_LO12_NC against symbol: dat
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+  ldrsb x0, [x1, :lo12:dat]
+.data
+.globl dat
+dat:
+  .word 0
diff --git a/test/ELF/aarch64-fpic-prel16.s b/test/ELF/aarch64-fpic-prel16.s
new file mode 100644 (file)
index 0000000..1faef9f
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: R_AARCH64_PREL16 cannot be used against shared object; recompile with -fPIC
+// CHECK: >>> defined in {{.*}}
+// CHECK: >>> referenced by {{.*}}:(.data+0x0)
+
+.data
+  .hword foo - .
diff --git a/test/ELF/aarch64-fpic-prel32.s b/test/ELF/aarch64-fpic-prel32.s
new file mode 100644 (file)
index 0000000..b797dca
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_PREL32 cannot be used against shared object; recompile with -fPIC
+// CHECK: >>> defined in {{.*}}
+// CHECK: >>> referenced by {{.*}}:(.data+0x0)
+
+.data
+  .word foo - .
diff --git a/test/ELF/aarch64-fpic-prel64.s b/test/ELF/aarch64-fpic-prel64.s
new file mode 100644 (file)
index 0000000..4c67837
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: relocation R_AARCH64_PREL64 cannot be used against shared object; recompile with -fPIC
+// CHECK: >>> defined in {{.*}}
+// CHECK: >>> referenced by {{.*}}:(.data+0x0)
+
+.data
+  .xword foo - .
diff --git a/test/ELF/aarch64-gnu-ifunc-nosym.s b/test/ELF/aarch64-gnu-ifunc-nosym.s
new file mode 100644 (file)
index 0000000..bb3a0b8
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: aarch64
+
+// Check that no __rela_iplt_end/__rela_iplt_start
+// appear in symtab if there is no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rela_iplt_end
+// CHECK-NOT: __rela_iplt_start
+// CHECK: ]
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ bl foo
+ bl bar
diff --git a/test/ELF/aarch64-gnu-ifunc-plt.s b/test/ELF/aarch64-gnu-ifunc-plt.s
new file mode 100644 (file)
index 0000000..be9a8a7
--- /dev/null
@@ -0,0 +1,85 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %S/Inputs/shared2.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: aarch64
+
+// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rela.plt {
+// CHECK:     0x30018 R_AARCH64_JUMP_SLOT bar2 0x0
+// CHECK-NEXT:     0x30020 R_AARCH64_JUMP_SLOT zed2 0x0
+// CHECK-NEXT:     0x30028 R_AARCH64_IRELATIVE - 0x20000
+// CHECK-NEXT:     0x30030 R_AARCH64_IRELATIVE - 0x20004
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Check that .got.plt entries point back to PLT header
+// GOTPLT: Contents of section .got.plt:
+// GOTPLT-NEXT:  30000 00000000 00000000 00000000 00000000
+// GOTPLT-NEXT:  30010 00000000 00000000 20000200 00000000
+// GOTPLT-NEXT:  30020 20000200 00000000 20000200 00000000
+// GOTPLT-NEXT:  30030 20000200 00000000
+
+// Check that the PLTRELSZ tag includes the IRELATIVE relocations
+// CHECK: DynamicSection [
+// CHECK:   0x0000000000000002 PLTRELSZ             96 (bytes)
+
+// Check that a PLT header is written and the ifunc entries appear last
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    20000: {{.*}} ret
+// DISASM:      bar:
+// DISASM-NEXT:    20004: {{.*}} ret
+// DISASM:      _start:
+// DISASM-NEXT:    20008: {{.*}} bl      #88
+// DISASM-NEXT:    2000c: {{.*}} bl      #100
+// DISASM-NEXT:    20010: {{.*}} bl      #48
+// DISASM-NEXT:    20014: {{.*}} bl      #60
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    20020: {{.*}} stp     x16, x30, [sp, #-16]!
+// DISASM-NEXT:    20024: {{.*}} adrp    x16, #65536
+// DISASM-NEXT:    20028: {{.*}} ldr     x17, [x16, #16]
+// DISASM-NEXT:    2002c: {{.*}} add     x16, x16, #16
+// DISASM-NEXT:    20030: {{.*}} br      x17
+// DISASM-NEXT:    20034: {{.*}} nop
+// DISASM-NEXT:    20038: {{.*}} nop
+// DISASM-NEXT:    2003c: {{.*}} nop
+// DISASM-NEXT:    20040: {{.*}} adrp    x16, #65536
+// DISASM-NEXT:    20044: {{.*}} ldr     x17, [x16, #24]
+// DISASM-NEXT:    20048: {{.*}} add     x16, x16, #24
+// DISASM-NEXT:    2004c: {{.*}} br      x17
+// DISASM-NEXT:    20050: {{.*}} adrp    x16, #65536
+// DISASM-NEXT:    20054: {{.*}} ldr     x17, [x16, #32]
+// DISASM-NEXT:    20058: {{.*}} add     x16, x16, #32
+// DISASM-NEXT:    2005c: {{.*}} br      x17
+// DISASM-NEXT:    20060: {{.*}} adrp    x16, #65536
+// DISASM-NEXT:    20064: {{.*}} ldr     x17, [x16, #40]
+// DISASM-NEXT:    20068: {{.*}} add     x16, x16, #40
+// DISASM-NEXT:    2006c: {{.*}} br      x17
+// DISASM-NEXT:    20070: {{.*}} adrp    x16, #65536
+// DISASM-NEXT:    20074: {{.*}} ldr     x17, [x16, #48]
+// DISASM-NEXT:    20078: {{.*}} add     x16, x16, #48
+// DISASM-NEXT:    2007c: {{.*}} br      x17
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ bl foo
+ bl bar
+ bl bar2
+ bl zed2
diff --git a/test/ELF/aarch64-gnu-ifunc.s b/test/ELF/aarch64-gnu-ifunc.s
new file mode 100644 (file)
index 0000000..46f4a29
--- /dev/null
@@ -0,0 +1,139 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: aarch64
+
+// CHECK:      Sections [
+// CHECK:       Section {
+// CHECK:       Index: 1
+// CHECK-NEXT:  Name: .rela.plt
+// CHECK-NEXT:  Type: SHT_RELA
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: [[RELA:.*]]
+// CHECK-NEXT:  Offset: 0x158
+// CHECK-NEXT:  Size: 48
+// CHECK-NEXT:  Link: 6
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 8
+// CHECK-NEXT:  EntrySize: 24
+// CHECK-NEXT: }
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x30000 R_AARCH64_IRELATIVE
+// CHECK-NEXT:     0x30008 R_AARCH64_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:      Symbols [
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name:
+// CHECK-NEXT:    Value: 0x0
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: Undefined
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: $x.0
+// CHECK-NEXT:    Value: 0x20000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_end
+// CHECK-NEXT:    Value: 0x10188
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_start
+// CHECK-NEXT:    Value: 0x10158
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: _start
+// CHECK-NEXT:    Value: 0x20008
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: bar
+// CHECK-NEXT:    Value: 0x20004
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: foo
+// CHECK-NEXT:    Value: 0x20000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT: ]
+
+// 344 = 0x158
+// 392 = 0x188
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:  20000: c0 03 5f d6 ret
+// DISASM: bar:
+// DISASM-NEXT:  20004: c0 03 5f d6 ret
+// DISASM:      _start:
+// DISASM-NEXT:  20008: 06 00 00 94 bl #24
+// DISASM-NEXT:  2000c: 09 00 00 94     bl      #36
+// DISASM-NEXT:  20010: 42 60 05 91     add     x2, x2, #344
+// DISASM-NEXT:  20014: 42 20 06 91     add     x2, x2, #392
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:  20020: 90 00 00 90 adrp x16, #65536
+// DISASM-NEXT:  20024: 11 02 40 f9 ldr x17, [x16]
+// DISASM-NEXT:  20028: 10 02 00 91 add x16, x16, #0
+// DISASM-NEXT:  2002c: 20 02 1f d6 br x17
+// DISASM-NEXT:  20030: 90 00 00 90 adrp x16, #65536
+// DISASM-NEXT:  20034: 11 06 40 f9 ldr x17, [x16, #8]
+// DISASM-NEXT:  20038: 10 22 00 91 add x16, x16, #8
+// DISASM-NEXT:  2003c: 20 02 1f d6 br x17
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ bl foo
+ bl bar
+ add x2, x2, :lo12:__rela_iplt_start
+ add x2, x2, :lo12:__rela_iplt_end
diff --git a/test/ELF/aarch64-got-reloc.s b/test/ELF/aarch64-got-reloc.s
new file mode 100644 (file)
index 0000000..fec1ad6
--- /dev/null
@@ -0,0 +1,30 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s --section-data  %t | FileCheck %s
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:    SHF_WRITE
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: 0x30000
+// CHECK-NEXT:  Offset: 0x20000
+// CHECK-NEXT:  Size: 8
+// CHECK-NEXT:  Link: 0
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 8
+// CHECK-NEXT:  EntrySize: 0
+// CHECK-NEXT:  SectionData (
+// CHECK-NEXT:    0000: 00000000 00000000                    |........|
+// CHECK-NEXT:  )
+
+        .globl  _start
+_start:
+        adrp    x8, :got:foo
+        ldr     x8, [x8, :got_lo12:foo]
+        ldr     w0, [x8]
+        ret
+
+        .weak   foo
diff --git a/test/ELF/aarch64-got-relocations.s b/test/ELF/aarch64-got-relocations.s
new file mode 100644 (file)
index 0000000..13ee09a
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-cloudabi %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# If we're addressing a global relatively through the GOT, we still need to
+# emit a relocation for the entry in the GOT itself.
+# CHECK: Relocations [
+# CHECK:   Section (4) .rela.dyn {
+# CHECK:     0x{{[0-9A-F]+}} R_AARCH64_RELATIVE - 0x{{[0-9A-F]+}}
+# CHECK:   }
+# CHECK: ]
+
+       .globl  _start
+       .type   _start,@function
+_start:
+       adrp    x8, :got:i
+       ldr     x8, [x8, :got_lo12:i]
+
+       .type   i,@object
+       .comm   i,4,4
diff --git a/test/ELF/aarch64-got.s b/test/ELF/aarch64-got.s
new file mode 100644 (file)
index 0000000..f56d8a7
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK-NOT: Name: .got
+
+.globl _start
+_start:
+ adrp    x0, :gottprel:foo
+
+       .global foo
+ .section .tdata,"awT",%progbits
+ .align 2
+ .type foo, %object
+ .size foo, 4
+foo:
+ .word 5
diff --git a/test/ELF/aarch64-hi21-error.s b/test/ELF/aarch64-hi21-error.s
new file mode 100644 (file)
index 0000000..9e2b283
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %tabs %t -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.globl _start
+_start:
+adrp x0, big
+
+#CHECK: R_AARCH64_ADR_PREL_PG_HI21 out of range
diff --git a/test/ELF/aarch64-jump26-error.s b/test/ELF/aarch64-jump26-error.s
new file mode 100644 (file)
index 0000000..81fbba1
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %t %tabs -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.text
+.globl _start
+_start:
+    b big
+
+// CHECK: R_AARCH64_JUMP26 out of range
diff --git a/test/ELF/aarch64-lo21-error.s b/test/ELF/aarch64-lo21-error.s
new file mode 100644 (file)
index 0000000..055f894
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t
+// RUN: not ld.lld %tabs %t -o %t2 2>&1 | FileCheck %s
+// REQUIRES: aarch64
+
+.globl _start
+_start:
+adr x0, big
+
+#CHECK: R_AARCH64_ADR_PREL_LO21 out of range
diff --git a/test/ELF/aarch64-prel16.s b/test/ELF/aarch64-prel16.s
new file mode 100644 (file)
index 0000000..4ae1f87
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .hword foo - . + 0x20eff
+  .hword foo - . + 0x8f02
+
+// Note: If this test fails, it probably happens because of
+//       the change of the address of the .data section.
+//       You may found the correct address in the aarch64_abs16.s test,
+//       if it is already fixed. Then, update addends accordingly.
+// RUN: ld.lld -z max-page-size=4096 %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 11000: S = 0x100, A = 0x20eff, P = 0x11000
+//        S + A - P = 0xffff
+// 11002: S = 0x100, A = 0x8f02, P = 0x11002
+//        S + A - P = 0x8000
+// CHECK-NEXT: 11000 ffff0080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_PREL16 out of range
diff --git a/test/ELF/aarch64-prel32.s b/test/ELF/aarch64-prel32.s
new file mode 100644 (file)
index 0000000..302f452
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs255.s -o %t255.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs257.s -o %t257.o
+
+.globl _start
+_start:
+.data
+  .word foo - . + 0x100010eff
+  .word foo - . - 0x7ffef0fc
+
+// Note: If this test fails, it probably happens because of
+//       the change of the address of the .data section.
+//       You may found the correct address in the aarch64_abs32.s test,
+//       if it is already fixed. Then, update addends accordingly.
+// RUN: ld.lld -z max-page-size=4096 %t.o %t256.o -o %t2
+// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
+
+// CHECK: Contents of section .data:
+// 11000: S = 0x100, A = 0x100010eff, P = 0x11000
+//        S + A - P = 0xffffffff
+// 11004: S = 0x100, A = -0x7ffef0fc, P = 0x11004
+//        S + A - P = 0x80000000
+// CHECK-NEXT: 11000 ffffffff 00000080
+
+// RUN: not ld.lld %t.o %t255.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// RUN: not ld.lld %t.o %t257.o -o %t2
+//   | FileCheck %s --check-prefix=OVERFLOW
+// OVERFLOW: Relocation R_AARCH64_PREL32 out of range
diff --git a/test/ELF/aarch64-relative.s b/test/ELF/aarch64-relative.s
new file mode 100644 (file)
index 0000000..b10dd80
--- /dev/null
@@ -0,0 +1,26 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r %t.so | FileCheck %s
+
+  adr     x8, .Lfoo                 // R_AARCH64_ADR_PREL_LO21
+  adrp    x8, .Lfoo                 // R_AARCH64_ADR_PREL_PG_HI21
+  strb    w9, [x8, :lo12:.Lfoo]     // R_AARCH64_LDST8_ABS_LO12_NC
+  ldr     h17, [x19, :lo12:.Lfoo]   // R_AARCH64_LDST16_ABS_LO12_NC
+  ldr     w0, [x8, :lo12:.Lfoo]     // R_AARCH64_LDST32_ABS_LO12_NC
+  ldr     x0, [x8, :lo12:.Lfoo]     // R_AARCH64_LDST64_ABS_LO12_NC
+  ldr     q20, [x19, #:lo12:.Lfoo]  // R_AARCH64_LDST128_ABS_LO12_NC
+  add     x0, x0, :lo12:.Lfoo       // R_AARCH64_ADD_ABS_LO12_NC
+  bl      .Lfoo                     // R_AARCH64_CALL26
+  b       .Lfoo                     // R_AARCH64_JUMP26
+  beq     .Lfoo                     // R_AARCH64_CONDBR19
+.Lbranch:
+  tbz     x1, 7, .Lbranch           // R_AARCH64_TSTBR14
+.data
+.Lfoo:
+
+.rodata
+.long .Lfoo - .
+.xword .Lfoo - .                    // R_AARCH64_PREL64
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
diff --git a/test/ELF/aarch64-relocs.s b/test/ELF/aarch64-relocs.s
new file mode 100644 (file)
index 0000000..9d02bd5
--- /dev/null
@@ -0,0 +1,174 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/uabs_label.s -o %t2.o
+# RUN: ld.lld %t %t2.o -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: aarch64
+
+.section .R_AARCH64_ADR_PREL_LO21,"ax",@progbits
+.globl _start
+_start:
+  adr x1,msg
+msg:  .asciz  "Hello, world\n"
+msgend:
+
+# CHECK: Disassembly of section .R_AARCH64_ADR_PREL_LO21:
+# CHECK: _start:
+# CHECK:        0:       21 00 00 10     adr     x1, #4
+# CHECK: msg:
+# CHECK:        4:
+# #4 is the adr immediate value.
+
+.section .R_AARCH64_ADR_PREL_PG_H121,"ax",@progbits
+  adrp x1,mystr
+mystr:
+  .asciz "blah"
+  .size mystr, 4
+
+# S = 0x20012, A = 0x4, P = 0x20012
+# PAGE(S + A) = 0x11000
+# PAGE(P) = 0x11000
+#
+# CHECK: Disassembly of section .R_AARCH64_ADR_PREL_PG_H121:
+# CHECK-NEXT: $x.2:
+# CHECK-NEXT:   20012:       01 00 00 90     adrp    x1, #0
+
+.section .R_AARCH64_ADD_ABS_LO12_NC,"ax",@progbits
+  add x0, x0, :lo12:.L.str
+.L.str:
+  .asciz "blah"
+  .size mystr, 4
+
+# S = 0x2001b, A = 0x4
+# R = (S + A) & 0xFFF = 0x1f
+# R << 10 = 0x7c00
+#
+# CHECK: Disassembly of section .R_AARCH64_ADD_ABS_LO12_NC:
+# CHECK-NEXT: $x.4:
+# CHECK-NEXT:   2001b:       00 7c 00 91     add     x0, x0, #31
+
+.section .R_AARCH64_LDST64_ABS_LO12_NC,"ax",@progbits
+  ldr x28, [x27, :lo12:foo]
+foo:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x20024, A = 0x4
+# R = ((S + A) & 0xFFF) << 7 = 0x00001400
+# 0x00001400 | 0xf940177c = 0xf940177c
+# CHECK: Disassembly of section .R_AARCH64_LDST64_ABS_LO12_NC:
+# CHECK-NEXT: $x.6:
+# CHECK-NEXT:   20024:       7c 17 40 f9     ldr     x28, [x27, #40]
+
+.section .SUB,"ax",@progbits
+  nop
+sub:
+  nop
+
+# CHECK: Disassembly of section .SUB:
+# CHECK-NEXT: $x.8:
+# CHECK-NEXT:   2002c:       1f 20 03 d5     nop
+# CHECK: sub:
+# CHECK-NEXT:   20030:       1f 20 03 d5     nop
+
+.section .R_AARCH64_CALL26,"ax",@progbits
+call26:
+        bl sub
+
+# S = 0x2002c, A = 0x4, P = 0x20034
+# R = S + A - P = -0x4 = 0xfffffffc
+# (R & 0x0ffffffc) >> 2 = 0x03ffffff
+# 0x94000000 | 0x03ffffff = 0x97ffffff
+# CHECK: Disassembly of section .R_AARCH64_CALL26:
+# CHECK-NEXT: call26:
+# CHECK-NEXT:   20034:       ff ff ff 97     bl     #-4
+
+.section .R_AARCH64_JUMP26,"ax",@progbits
+jump26:
+        b sub
+
+# S = 0x2002c, A = 0x4, P = 0x20038
+# R = S + A - P = -0x8 = 0xfffffff8
+# (R & 0x0ffffffc) >> 2 = 0x03fffffe
+# 0x14000000 | 0x03fffffe = 0x17fffffe
+# CHECK: Disassembly of section .R_AARCH64_JUMP26:
+# CHECK-NEXT: jump26:
+# CHECK-NEXT:   20038:       fe ff ff 17     b      #-8
+
+.section .R_AARCH64_LDST32_ABS_LO12_NC,"ax",@progbits
+ldst32:
+  ldr s4, [x5, :lo12:foo32]
+foo32:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x2003c, A = 0x4
+# R = ((S + A) & 0xFFC) << 8 = 0x00004000
+# 0x00004000 | 0xbd4000a4 = 0xbd4040a4
+# CHECK: Disassembly of section .R_AARCH64_LDST32_ABS_LO12_NC:
+# CHECK-NEXT: ldst32:
+# CHECK-NEXT:   2003c:       a4 40 40 bd     ldr s4, [x5, #64]
+
+.section .R_AARCH64_LDST8_ABS_LO12_NC,"ax",@progbits
+ldst8:
+  ldrsb x11, [x13, :lo12:foo8]
+foo8:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x20044, A = 0x4
+# R = ((S + A) & 0xFFF) << 10 = 0x00012000
+# 0x00012000 | 0x398001ab = 0x398121ab
+# CHECK: Disassembly of section .R_AARCH64_LDST8_ABS_LO12_NC:
+# CHECK-NEXT: ldst8:
+# CHECK-NEXT:   20044:       ab 21 81 39     ldrsb x11, [x13, #72]
+
+.section .R_AARCH64_LDST128_ABS_LO12_NC,"ax",@progbits
+ldst128:
+  ldr q20, [x19, #:lo12:foo128]
+foo128:
+  .asciz "foo"
+  .size mystr, 3
+
+# S = 0x2004c, A = 0x4
+# R = ((S + A) & 0xFF8) << 6 = 0x00001400
+# 0x00001400 | 0x3dc00274 = 0x3dc01674
+# CHECK: Disassembly of section .R_AARCH64_LDST128_ABS_LO12_NC:
+# CHECK: ldst128:
+# CHECK:   2004c:       74 16 c0 3d     ldr     q20, [x19, #80]
+#foo128:
+#   20050:       66 6f 6f 00     .word
+
+.section .R_AARCH64_LDST16_ABS_LO12_NC,"ax",@progbits
+ldst16:
+  ldr h17, [x19, :lo12:foo16]
+  ldrh w1, [x19, :lo12:foo16]
+  ldrh w2, [x19, :lo12:foo16 + 2]
+foo16:
+  .asciz "foo"
+  .size mystr, 4
+
+# S = 0x20054, A = 0x4
+# R = ((S + A) & 0x0FFC) << 9 = 0xb000
+# 0xb000 | 0x7d400271 = 0x7d40b271
+# CHECK: Disassembly of section .R_AARCH64_LDST16_ABS_LO12_NC:
+# CHECK-NEXT: ldst16:
+# CHECK-NEXT:   20054:       71 c2 40 7d     ldr     h17, [x19, #96]
+# CHECK-NEXT:   20058:       61 c2 40 79     ldrh    w1, [x19, #96]
+# CHECK-NEXT:   2005c:       62 c6 40 79     ldrh    w2, [x19, #98]
+
+.section .R_AARCH64_MOVW_UABS,"ax",@progbits
+movz1:
+   movk x12, #:abs_g0_nc:uabs_label
+   movk x13, #:abs_g1_nc:uabs_label
+   movk x14, #:abs_g2_nc:uabs_label
+   movz x15, #:abs_g3:uabs_label
+   movk x16, #:abs_g3:uabs_label
+
+## 4222124650659840 == (0xF << 48)
+# CHECK: Disassembly of section .R_AARCH64_MOVW_UABS:
+# CHECK-NEXT: movz1:
+# CHECK-NEXT: 8c 01 80 f2   movk  x12, #12
+# CHECK-NEXT: ad 01 a0 f2   movk  x13, #13, lsl #16
+# CHECK-NEXT: ce 01 c0 f2   movk  x14, #14, lsl #32
+# CHECK-NEXT: ef 01 e0 d2   mov x15, #4222124650659840
+# CHECK-NEXT: f0 01 e0 f2   movk  x16, #15, lsl #48
diff --git a/test/ELF/aarch64-relro.s b/test/ELF/aarch64-relro.s
new file mode 100644 (file)
index 0000000..3ec19d7
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK:      Type: PT_GNU_RELRO
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: VirtualAddress:
+# CHECK-NEXT: PhysicalAddress:
+# CHECK-NEXT: FileSize:
+# CHECK-NEXT: MemSize: 4096
+
+.section .data.rel.ro,"aw",%progbits
+.byte 1
diff --git a/test/ELF/aarch64-tls-gdie.s b/test/ELF/aarch64-tls-gdie.s
new file mode 100644 (file)
index 0000000..c66ea6c
--- /dev/null
@@ -0,0 +1,34 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: llvm-mc %p/Inputs/aarch64-tls-gdie.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s %t | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d %t | FileCheck %s
+
+        .globl  _start
+_start:
+        nop
+        adrp    x0, :tlsdesc:a
+        ldr     x1, [x0, :tlsdesc_lo12:a]
+        add     x0, x0, :tlsdesc_lo12:a
+        .tlsdesccall a
+        blr     x1
+
+// SEC:      Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x300B0
+
+// page(0x300B0) - page(0x20004) = 65536
+// 0x0B0 = 176
+
+// CHECK:      _start:
+// CHECK-NEXT: 20000: {{.*}} nop
+// CHECK-NEXT: 20004: {{.*}} adrp       x0, #65536
+// CHECK-NEXT: 20008: {{.*}} ldr        x0, [x0, #176]
+// CHECK-NEXT: 2000c: {{.*}} nop
+// CHECK-NEXT: 20010: {{.*}} nop
diff --git a/test/ELF/aarch64-tls-gdle.s b/test/ELF/aarch64-tls-gdle.s
new file mode 100644 (file)
index 0000000..a111cac
--- /dev/null
@@ -0,0 +1,26 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o
+# RUN: ld.lld %tmain.o %ttlsie.o -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+#Local-Dynamic to Initial-Exec relax creates no
+#RELOC:      Relocations [
+#RELOC-NEXT: ]
+
+# TCB size = 0x16 and foo is first element from TLS register.
+# CHECK: Disassembly of section .text:
+# CHECK: _start:
+# CHECK:  20000:       00 00 a0 d2     movz    x0, #0, lsl #16
+# CHECK:  20004:       00 02 80 f2     movk    x0, #16
+# CHECK:  20008:       1f 20 03 d5     nop
+# CHECK:  2000c:       1f 20 03 d5     nop
+
+.globl _start
+_start:
+ adrp    x0, :tlsdesc:foo
+ ldr     x1, [x0, :tlsdesc_lo12:foo]
+ add     x0, x0, :tlsdesc_lo12:foo
+ .tlsdesccall foo
+ blr     x1
diff --git a/test/ELF/aarch64-tls-ie.s b/test/ELF/aarch64-tls-ie.s
new file mode 100644 (file)
index 0000000..81ca326
--- /dev/null
@@ -0,0 +1,50 @@
+// REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-tls-ie.s -o %tdso.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o
+# RUN: ld.lld -shared %tdso.o -o %tdso.so
+# RUN: ld.lld %tmain.o %tdso.so -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+#RELOC:      Section {
+#RELOC:        Index:
+#RELOC:        Name: .got
+#RELOC-NEXT:   Type: SHT_PROGBITS
+#RELOC-NEXT:   Flags [
+#RELOC-NEXT:     SHF_ALLOC
+#RELOC-NEXT:     SHF_WRITE
+#RELOC-NEXT:   ]
+#RELOC-NEXT:   Address: 0x300B0
+#RELOC-NEXT:   Offset: 0x200B0
+#RELOC-NEXT:   Size: 16
+#RELOC-NEXT:   Link: 0
+#RELOC-NEXT:   Info: 0
+#RELOC-NEXT:   AddressAlignment: 8
+#RELOC-NEXT:   EntrySize: 0
+#RELOC-NEXT: }
+#RELOC:      Relocations [
+#RELOC-NEXT:  Section ({{.*}}) .rela.dyn {
+#RELOC-NEXT:    0x300B8 R_AARCH64_TLS_TPREL64 bar 0x0
+#RELOC-NEXT:    0x300B0 R_AARCH64_TLS_TPREL64 foo 0x0
+#RELOC-NEXT:  }
+#RELOC-NEXT:]
+
+# Page(0x300B0) - Page(0x20000) = 0x10000 = 65536
+# 0x300B0 & 0xff8 = 0xB0 = 176
+# Page(0x300B8) - Page(0x20000) = 0x10000 = 65536
+# 0x300B8 & 0xff8 = 0xB8 = 184
+#CHECK: Disassembly of section .text:
+#CHECK: _start:
+#CHECK:  20000: 80 00 00 90 adrp x0, #65536
+#CHECK:  20004: 00 58 40 f9 ldr  x0, [x0, #176]
+#CHECK:  20008: 80 00 00 90 adrp x0, #65536
+#CHECK:  2000c: 00 5c 40 f9 ldr  x0, [x0, #184]
+
+.globl _start
+_start:
+ adrp x0, :gottprel:foo
+ ldr x0, [x0, #:gottprel_lo12:foo]
+
+ adrp x0, :gottprel:bar
+ ldr x0, [x0, #:gottprel_lo12:bar]
diff --git a/test/ELF/aarch64-tls-iele.s b/test/ELF/aarch64-tls-iele.s
new file mode 100644 (file)
index 0000000..208b5cd
--- /dev/null
@@ -0,0 +1,33 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o
+# RUN: ld.lld %tmain.o %ttlsie.o -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+# Initial-Exec to Local-Exec relax creates no dynamic relocations.
+# RELOC:      Relocations [
+# RELOC-NEXT: ]
+
+# TCB size = 0x16 and foo is first element from TLS register.
+# CHECK: Disassembly of section .text:
+# CHECK: _start:
+# CHECK-NEXT: 20000:  00 00 a0 d2   movz   x0, #0, lsl #16
+# CHECK-NEXT: 20004:  80 02 80 f2   movk   x0, #20
+# CHECK-NEXT: 20008:  00 00 a0 d2   movz   x0, #0, lsl #16
+# CHECK-NEXT: 2000c:  00 02 80 f2   movk   x0, #16
+
+.section .tdata
+.align 2
+.type foo_local, %object
+.size foo_local, 4
+foo_local:
+.word 5
+.text
+
+.globl _start
+_start:
+ adrp    x0, :gottprel:foo
+ ldr     x0, [x0, :gottprel_lo12:foo]
+ adrp    x0, :gottprel:foo_local
+ ldr     x0, [x0, :gottprel_lo12:foo_local]
diff --git a/test/ELF/aarch64-tls-le.s b/test/ELF/aarch64-tls-le.s
new file mode 100644 (file)
index 0000000..df943f7
--- /dev/null
@@ -0,0 +1,31 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o
+# RUN: ld.lld %tmain.o -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck %s
+# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
+# REQUIRES: aarch64
+
+#Local-Dynamic to Initial-Exec relax creates no
+#RELOC:      Relocations [
+#RELOC-NEXT: ]
+
+.globl _start
+_start:
+ mrs x0, TPIDR_EL0
+ add x0, x0, :tprel_hi12:v1
+ add x0, x0, :tprel_lo12_nc:v1
+
+# TCB size = 0x16 and foo is first element from TLS register.
+#CHECK: Disassembly of section .text:
+#CHECK: _start:
+#CHECK:  20000: 40 d0 3b d5     mrs     x0, TPIDR_EL0
+#CHECK:  20004: 00 00 40 91     add     x0, x0, #0, lsl #12
+#CHECK:  20008: 00 40 00 91     add     x0, x0, #16
+
+.type   v1,@object
+.section        .tbss,"awT",@nobits
+.globl  v1
+.p2align 2
+v1:
+.word  0
+.size  v1, 4
+
diff --git a/test/ELF/aarch64-tls-pie.s b/test/ELF/aarch64-tls-pie.s
new file mode 100644 (file)
index 0000000..466045d
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-cloudabi %s -o %t1.o
+# RUN: ld.lld -pie %t1.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# Similar to bug 27174: R_AARCH64_TLSLE_*TPREL* relocations should be
+# eliminated when building a PIE executable, as the static TLS layout is
+# fixed.
+#
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+
+       .globl  _start
+_start:
+       # Accessing the variable directly.
+       add     x11, x8, :tprel_hi12:i
+       add     x11, x11, :tprel_lo12_nc:i
+
+       # Accessing the variable through the GOT.
+       adrp    x10, :gottprel:i
+       mrs     x8, TPIDR_EL0
+       ldr     x10, [x10, :gottprel_lo12:i]
+
+       .section        .tbss.i,"awT",@nobits
+       .globl  i
+i:
+       .word   0
+       .size   i, 4
diff --git a/test/ELF/aarch64-tls-static.s b/test/ELF/aarch64-tls-static.s
new file mode 100644 (file)
index 0000000..24306d5
--- /dev/null
@@ -0,0 +1,37 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc %s -o %t.o -triple aarch64-pc-linux -filetype=obj
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+foo:
+        adrp    x0, :tlsdesc:bar
+        ldr     x1, [x0, :tlsdesc_lo12:bar]
+        add     x0, x0, :tlsdesc_lo12:bar
+        .tlsdesccall bar
+        blr     x1
+
+
+        .section        .tdata,"awT",@progbits
+bar:
+        .word   42
+
+
+// SEC:      Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x20098
+// SEC-NEXT: Offset: 0x20098
+// SEC-NEXT: Size: 16
+
+// page(0x20098) - page(0x10000) = 65536
+// 0x98 = 152
+
+// CHECK:      foo:
+// CHECK-NEXT: 10000: {{.*}} adrp x0, #65536
+// CHECK-NEXT: 10004: {{.*}} ldr  x1, [x0, #152]
+// CHECK-NEXT: 10008: {{.*}} add  x0, x0, #152
+// CHECK-NEXT: 1000c: {{.*}} blr  x1
diff --git a/test/ELF/aarch64-tlsdesc.s b/test/ELF/aarch64-tlsdesc.s
new file mode 100644 (file)
index 0000000..09dfd04
--- /dev/null
@@ -0,0 +1,72 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+// RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=REL %s
+
+       .text
+        adrp    x0, :tlsdesc:a
+        ldr     x1, [x0, :tlsdesc_lo12:a]
+        add     x0, x0, :tlsdesc_lo12:a
+        .tlsdesccall a
+        blr     x1
+
+// Create relocation against local TLS symbols where linker should
+// create target specific dynamic TLSDESC relocation where addend is
+// the symbol VMA in tls block.
+
+// CHECK:      10000: {{.*}}  adrp    x0, #65536
+// CHECK-NEXT: 10004: {{.*}}  ldr     x1, [x0, #144]
+// CHECK-NEXT: 10008: {{.*}}  add     x0, x0, #144
+// CHECK-NEXT: 1000c: {{.*}}  blr     x1
+
+       adrp    x0, :tlsdesc:local1
+       ldr     x1, [x0, :tlsdesc_lo12:local1]
+       add     x0, x0, :tlsdesc_lo12:local1
+        .tlsdesccall a
+        blr     x1
+
+// CHECK:      10010: {{.*}}  adrp    x0, #65536
+// CHECK-NEXT: 10014: {{.*}}  ldr     x1, [x0, #160]
+// CHECK-NEXT: 10018: {{.*}}  add     x0, x0, #160
+// CHECK-NEXT: 1001c: {{.*}}  blr     x1
+
+       adrp    x0, :tlsdesc:local2
+       ldr     x1, [x0, :tlsdesc_lo12:local2]
+       add     x0, x0, :tlsdesc_lo12:local2
+        .tlsdesccall a
+        blr     x1
+
+// CHECK:      10020: {{.*}}  adrp    x0, #65536
+// CHECK-NEXT: 10024: {{.*}}  ldr     x1, [x0, #176]
+// CHECK-NEXT: 10028: {{.*}}  add     x0, x0, #176
+// CHECK-NEXT: 1002c: {{.*}}  blr     x1
+
+        .section .tbss,"awT",@nobits
+        .type   local1,@object
+        .p2align 2
+local1:
+        .word   0
+        .size   local1, 4
+
+        .type   local2,@object
+        .p2align 3
+local2:
+        .xword  0
+        .size   local2, 8
+
+
+// 0x1000 + 4096 + 160 = 0x20A0
+// 0x1000 + 4096 + 176 = 0x20B0
+// 0x1000 + 4096 + 144 = 0x2090
+
+// R_AARCH64_TLSDESC - 0x0 -> start of tls block
+// R_AARCH64_TLSDESC - 0x8 -> align (sizeof (local1), 8)
+
+// REL:      Relocations [
+// REL-NEXT:   Section (4) .rela.dyn {
+// REL-NEXT:     0x200A0 R_AARCH64_TLSDESC - 0x0
+// REL-NEXT:     0x200B0 R_AARCH64_TLSDESC - 0x8
+// REL-NEXT:     0x20090 R_AARCH64_TLSDESC a 0x0
+// REL-NEXT:   }
+// REL-NEXT: ]
diff --git a/test/ELF/aarch64-tstbr14-reloc.s b/test/ELF/aarch64-tstbr14-reloc.s
new file mode 100644 (file)
index 0000000..c0a0a54
--- /dev/null
@@ -0,0 +1,96 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-tstbr14-reloc.s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld -shared %t1 %t2 -o %t3
+# RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s
+# RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+# REQUIRES: aarch64
+
+# 0x1101c - 28 = 0x20000
+# 0x11020 - 16 = 0x20010
+# 0x11024 - 36 = 0x20000
+# 0x11028 - 24 = 0x20010
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: _foo:
+# CHECK-NEXT:  20000: {{.*}} nop
+# CHECK-NEXT:  20004: {{.*}} nop
+# CHECK-NEXT:  20008: {{.*}} nop
+# CHECK-NEXT:  2000c: {{.*}} nop
+# CHECK:      _bar:
+# CHECK-NEXT:  20010: {{.*}} nop
+# CHECK-NEXT:  20014: {{.*}} nop
+# CHECK-NEXT:  20018: {{.*}} nop
+# CHECK:      _start:
+# CHECK-NEXT:  2001c: {{.*}} tbnz w3, #15, #-28
+# CHECK-NEXT:  20020: {{.*}} tbnz w3, #15, #-16
+# CHECK-NEXT:  20024: {{.*}} tbz x6, #45, #-36
+# CHECK-NEXT:  20028: {{.*}} tbz x6, #45, #-24
+
+#DSOREL:      Section {
+#DSOREL:        Index:
+#DSOREL:        Name: .got.plt
+#DSOREL-NEXT:   Type: SHT_PROGBITS
+#DSOREL-NEXT:   Flags [
+#DSOREL-NEXT:     SHF_ALLOC
+#DSOREL-NEXT:     SHF_WRITE
+#DSOREL-NEXT:   ]
+#DSOREL-NEXT:   Address: 0x20000
+#DSOREL-NEXT:   Offset: 0x20000
+#DSOREL-NEXT:   Size: 40
+#DSOREL-NEXT:   Link: 0
+#DSOREL-NEXT:   Info: 0
+#DSOREL-NEXT:   AddressAlignment: 8
+#DSOREL-NEXT:   EntrySize: 0
+#DSOREL-NEXT:  }
+#DSOREL:      Relocations [
+#DSOREL-NEXT:  Section ({{.*}}) .rela.plt {
+#DSOREL-NEXT:    0x20018 R_AARCH64_JUMP_SLOT _foo
+#DSOREL-NEXT:    0x20020 R_AARCH64_JUMP_SLOT _bar
+#DSOREL-NEXT:  }
+#DSOREL-NEXT:]
+
+#DSO:      Disassembly of section .text:
+#DSO-NEXT: _foo:
+#DSO-NEXT:  10000: {{.*}} nop
+#DSO-NEXT:  10004: {{.*}} nop
+#DSO-NEXT:  10008: {{.*}} nop
+#DSO-NEXT:  1000c: {{.*}} nop
+#DSO:      _bar:
+#DSO-NEXT:  10010: {{.*}} nop
+#DSO-NEXT:  10014: {{.*}} nop
+#DSO-NEXT:  10018: {{.*}} nop
+#DSO:      _start:
+# 0x1001c + 52 = 0x10050 = PLT[1]
+# 0x10020 + 64 = 0x10060 = PLT[2]
+# 0x10024 + 44 = 0x10050 = PLT[1]
+# 0x10028 + 56 = 0x10060 = PLT[2]
+#DSO-NEXT:  1001c: {{.*}} tbnz w3, #15, #52
+#DSO-NEXT:  10020: {{.*}} tbnz w3, #15, #64
+#DSO-NEXT:  10024: {{.*}} tbz x6, #45, #44
+#DSO-NEXT:  10028: {{.*}} tbz x6, #45, #56
+#DSO-NEXT: Disassembly of section .plt:
+#DSO-NEXT: .plt:
+#DSO-NEXT:  10030: {{.*}} stp x16, x30, [sp, #-16]!
+#DSO-NEXT:  10034: {{.*}} adrp x16, #65536
+#DSO-NEXT:  10038: {{.*}} ldr x17, [x16, #16]
+#DSO-NEXT:  1003c: {{.*}} add x16, x16, #16
+#DSO-NEXT:  10040: {{.*}} br x17
+#DSO-NEXT:  10044: {{.*}} nop
+#DSO-NEXT:  10048: {{.*}} nop
+#DSO-NEXT:  1004c: {{.*}} nop
+#DSO-NEXT:  10050: {{.*}} adrp x16, #65536
+#DSO-NEXT:  10054: {{.*}} ldr x17, [x16, #24]
+#DSO-NEXT:  10058: {{.*}} add x16, x16, #24
+#DSO-NEXT:  1005c: {{.*}} br x17
+#DSO-NEXT:  10060: {{.*}} adrp x16, #65536
+#DSO-NEXT:  10064: {{.*}} ldr x17, [x16, #32]
+#DSO-NEXT:  10068: {{.*}} add x16, x16, #32
+#DSO-NEXT:  1006c: {{.*}} br x17
+
+.globl _start
+_start:
+ tbnz w3, #15, _foo
+ tbnz w3, #15, _bar
+ tbz x6, #45, _foo
+ tbz x6, #45, _bar
diff --git a/test/ELF/aarch64-undefined-weak.s b/test/ELF/aarch64-undefined-weak.s
new file mode 100644 (file)
index 0000000..1c21213
--- /dev/null
@@ -0,0 +1,45 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -triple=aarch64-none-linux -d %t2 | FileCheck %s
+// REQUIRES: aarch64
+
+// Check that the ARM 64-bit ABI rules for undefined weak symbols are applied.
+// Branch instructions are resolved to the next instruction. Undefined
+// Symbols in relative are resolved to the place so S - P + A = A.
+
+ .weak target
+
+ .text
+ .global _start
+_start:
+// R_AARCH64_JUMP26
+ b target
+// R_AARCH64_CALL26
+ bl target
+// R_AARCH64_CONDBR19
+ b.eq target
+// R_AARCH64_TSTBR14
+ cbz x1, target
+// R_AARCH64_ADR_PREL_LO21
+ adr x0, target
+// R_AARCH64_ADR_PREL_PG_HI21
+ adrp x0, target
+// R_AARCH64_PREL32
+ .word target - .
+// R_AARCH64_PREL64
+ .xword target - .
+// R_AARCH64_PREL16
+ .hword target - .
+
+// CHECK: Disassembly of section .text:
+// 131076 = 0x20004
+// CHECK:         20000: {{.*}} b       #4
+// CHECK-NEXT:    20004: {{.*}} bl      #4
+// CHECK-NEXT:    20008: {{.*}} b.eq    #4
+// CHECK-NEXT:    2000c: {{.*}} cbz     x1, #4
+// CHECK-NEXT:    20010: {{.*}} adr     x0, #0
+// CHECK-NEXT:    20014: {{.*}} adrp    x0, #-131072
+// CHECK:         20018: {{.*}} .word   0x00000000
+// CHECK-NEXT:    2001c: {{.*}} .word   0x00000000
+// CHECK-NEXT:    20020: {{.*}} .word   0x00000000
+// CHECK-NEXT:    20024: {{.*}} .short  0x0000
diff --git a/test/ELF/abs-conflict.s b/test/ELF/abs-conflict.s
new file mode 100644 (file)
index 0000000..4662c48
--- /dev/null
@@ -0,0 +1,18 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %t.o -o %t.so -shared
+// RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x123
+
+.global foo
+foo = 0x123
+
+// RUN: echo ".global foo; foo = 0x124" >  %t2.s
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2.o
+// RUN: not ld.lld %t.o %t2.o -o %t.so -shared 2>&1 | FileCheck --check-prefix=DUP %s
+
+// DUP:      duplicate symbol: foo
+// DUP-NEXT: >>> defined in {{.*}}.o
+// DUP-NEXT: >>> defined in <internal>
diff --git a/test/ELF/abs-hidden.s b/test/ELF/abs-hidden.s
new file mode 100644 (file)
index 0000000..5fad4cf
--- /dev/null
@@ -0,0 +1,46 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/abs-hidden.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t.so -shared
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+        .quad foo
+        .long foo@gotpcrel
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 12
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 42000000 00000000 58100000
+//                                       0x2060 - (0x1000 + 8) = 1058
+// CHECK-NEXT: )
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2060
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 42000000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
diff --git a/test/ELF/allow-multiple-definition.s b/test/ELF/allow-multiple-definition.s
new file mode 100644 (file)
index 0000000..e4637e1
--- /dev/null
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/allow-multiple-definition.s -o %t2
+# RUN: not ld.lld %t1 %t2 -o %t3
+# RUN: ld.lld --allow-multiple-definition %t1 %t2 -o %t3
+# RUN: ld.lld --allow-multiple-definition %t2 %t1 -o %t4
+# RUN: llvm-objdump -d %t3 | FileCheck %s
+# RUN: llvm-objdump -d %t4 | FileCheck -check-prefix=REVERT %s
+
+# inputs contain different constants for instuction movl.
+# Tests below checks that order of files in command line
+# affects on what symbol will be used.
+# If flag allow-multiple-definition is enabled the first
+# meet symbol should be used.
+
+# CHECK: _bar:
+# CHECK-NEXT: 201000:   b8 01 00 00 00   movl   $1, %eax
+
+# REVERT: _bar:
+# REVERT-NEXT: 201000:   b8 02 00 00 00   movl   $2, %eax
+
+.globl _bar
+.type _bar, @function
+_bar:
+  mov $1, %eax
+
+.globl _start
+_start:
diff --git a/test/ELF/allow-shlib-undefined.s b/test/ELF/allow-shlib-undefined.s
new file mode 100644 (file)
index 0000000..abb0351
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# --allow-shlib-undefined and --no-allow-shlib-undefined are fully
+# ignored in linker implementation.
+# --allow-shlib-undefined is set by default
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/allow-shlib-undefined.s -o %t
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+
+# Executable: should link with DSO containing undefined symbols in any case.
+# RUN: ld.lld %t1 %t.so -o %t2
+# RUN: ld.lld --no-allow-shlib-undefined %t1 %t.so -o %t2
+# RUN: ld.lld --allow-shlib-undefined %t1 %t.so -o %t2
+
+# DSO with undefines:
+# should link with or without any of these options.
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: ld.lld -shared --allow-shlib-undefined %t -o %t.so
+# RUN: ld.lld -shared --no-allow-shlib-undefined %t -o %t.so
+
+# Executable still should not link when have undefines inside.
+# RUN: not ld.lld %t -o %t.so
+
+.globl _start
+_start:
+  callq _shared@PLT
diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s
new file mode 100644 (file)
index 0000000..e32159b
--- /dev/null
@@ -0,0 +1,64 @@
+# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t
+# RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s
+
+# REQUIRES: amdgpu
+
+.type glob0, @object
+.data
+  .globl glob0
+glob0:
+  .long 1
+  .size glob0, 4
+
+.type glob1, @object
+.section .rodata, #alloc
+  .globl glob1
+glob1:
+  .long 2
+  .size glob1, 4
+
+# CHECK: Section {
+# CHECK:   Name: .rodata
+# CHECK:   Type: SHT_PROGBITS
+# CHECK:   Flags [ (0x2)
+# CHECK:     SHF_ALLOC (0x2)
+# CHECK:   ]
+# CHECK:   Address: [[RODATA_ADDR:[0-9xa-f]+]]
+# CHECK: }
+
+# CHECK: Section {
+# CHECK:   Name: .data
+# CHECK:   Type: SHT_PROGBITS
+# CHECK:   Flags [ (0x3)
+# CHECK:     SHF_ALLOC (0x2)
+# CHECK:     SHF_WRITE (0x1)
+# CHECK:   ]
+# CHECK:   Address: [[DATA_ADDR:[0-9xa-f]+]]
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK:   Name: glob0
+# CHECK:   Value: [[DATA_ADDR]]
+# CHECK:   Size: 4
+# CHECK:   Type: Object
+# CHECK:   Section: .data
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK:   Name: glob1
+# CHECK:   Value: [[RODATA_ADDR]]
+# CHECK:   Size: 4
+# CHECK:   Type: Object
+# CHECK:   Section: .rodata
+# CHECK: }
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: VirtualAddress:
+# CHECK: }
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: VirtualAddress:
+# CHECK: }
diff --git a/test/ELF/amdgpu-kernels.s b/test/ELF/amdgpu-kernels.s
new file mode 100644 (file)
index 0000000..c76613f
--- /dev/null
@@ -0,0 +1,59 @@
+# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t
+# RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s
+
+# REQUIRES: amdgpu
+
+.hsa_code_object_version 1,0
+.hsa_code_object_isa 7,0,0,"AMD","AMDGPU"
+
+.text
+.globl kernel0
+.align 256
+.amdgpu_hsa_kernel kernel0
+kernel0:
+  s_endpgm
+.Lfunc_end0:
+  .size kernel0, .Lfunc_end0-kernel0
+
+.globl kernel1
+.align 256
+.amdgpu_hsa_kernel kernel1
+kernel1:
+  s_endpgm
+  s_endpgm
+.Lfunc_end1:
+  .size kernel1, .Lfunc_end1-kernel1
+
+
+# CHECK: Section {
+# CHECK: Name: .text
+# CHECK: Type: SHT_PROGBITS
+# CHECK: Flags [ (0x6)
+# CHECK: SHF_ALLOC (0x2)
+# CHECK: SHF_EXECINSTR (0x4)
+# CHECK: ]
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: kernel0
+# CHECK: Value:
+# CHECK: Size: 4
+# CHECK: Binding: Global
+# CHECK: Type: AMDGPU_HSA_KERNEL
+# CHECK: Section: .text
+# CHECK: }
+
+# CHECK: Symbol {
+# CHECK: Name: kernel1
+# CHECK: Value:
+# CHECK: Size: 8
+# CHECK: Binding: Global
+# CHECK: Type: AMDGPU_HSA_KERNEL
+# CHECK: Section: .text
+# CHECK: }
+
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD
+# CHECK: VirtualAddress:
+# CHECK: }
diff --git a/test/ELF/amdgpu-relocs.s b/test/ELF/amdgpu-relocs.s
new file mode 100644 (file)
index 0000000..1adb1fa
--- /dev/null
@@ -0,0 +1,93 @@
+# RUN: llvm-mc -filetype=obj -triple=amdgcn--amdhsa -mcpu=fiji %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck %s
+# RUN: llvm-objdump -s %t.so | FileCheck %s --check-prefix=OBJDUMP
+
+# REQUIRES: amdgpu
+
+.text
+
+kernel0:
+  s_mov_b32 s0, common_var0@GOTPCREL+4
+  s_mov_b32 s0, common_var1@gotpcrel32@lo+4
+  s_mov_b32 s0, common_var2@gotpcrel32@hi+4
+
+  s_mov_b32 s0, global_var0@GOTPCREL+4
+  s_mov_b32 s0, global_var1@gotpcrel32@lo+4
+  s_mov_b32 s0, global_var2@gotpcrel32@hi+4
+
+  s_mov_b32 s0, extern_var0@GOTPCREL+4
+  s_mov_b32 s0, extern_var1@gotpcrel32@lo+4
+  s_mov_b32 s0, extern_var2@gotpcrel32@hi+4
+
+  s_mov_b32 s0, weak_var0@GOTPCREL+4
+  s_mov_b32 s0, weak_var1@gotpcrel32@lo+4
+  s_mov_b32 s0, weak_var2@gotpcrel32@hi+4
+
+  s_mov_b32 s0, weakref_var0@GOTPCREL+4
+  s_mov_b32 s0, weakref_var1@gotpcrel32@lo+4
+  s_mov_b32 s0, weakref_var2@gotpcrel32@hi+4
+
+  s_mov_b32 s0, local_var0+4
+  s_mov_b32 s0, local_var1@rel32@lo+4
+  s_mov_b32 s0, local_var2@rel32@hi+4
+
+  s_endpgm
+
+  .comm    common_var0,1024,4
+  .comm    common_var1,1024,4
+  .comm    common_var2,1024,4
+  .globl   global_var0
+  .globl   global_var1
+  .globl   global_var1
+  .weak    weak_var0
+  .weak    weak_var1
+  .weak    weak_var2
+  .weakref weakref_var0, weakref_alias_var0
+  .weakref weakref_var1, weakref_alias_var1
+  .weakref weakref_var2, weakref_alias_var2
+  .local   local_var0
+  .local   local_var1
+  .local   local_var2
+
+# R_AMDGPU_ABS32:
+.section nonalloc, "w", @progbits
+  .long var0, common_var2+4
+  .long var1, common_var1+8
+  .long var2, common_var0+12
+
+# R_AMDGPU_ABS64:
+.type ptr, @object
+.data
+  .globl ptr
+  .p2align 3
+ptr:
+  .quad temp
+  .size ptr, 8
+
+# The relocation for local_var{0, 1, 2} and var should be resolved by the
+# linker.
+# CHECK: Relocations [
+# CHECK: .rela.dyn {
+# CHECK-NEXT: R_AMDGPU_ABS64 common_var0 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 common_var1 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 common_var2 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 extern_var0 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 extern_var1 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 extern_var2 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 global_var0 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 global_var1 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 global_var2 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 temp 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weak_var0 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weak_var1 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weak_var2 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weakref_alias_var0 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weakref_alias_var1 0x0
+# CHECK-NEXT: R_AMDGPU_ABS64 weakref_alias_var2 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# OBJDUMP: Contents of section nonalloc:
+# OBJDUMP-NEXT: 0000 00000000 04480000 00000000 08440000
+# OBJDUMP-NEXT: 00000000 0c400000
diff --git a/test/ELF/archive.s b/test/ELF/archive.s
new file mode 100644 (file)
index 0000000..59c96a5
--- /dev/null
@@ -0,0 +1,40 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive.s -o %t2
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t3
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive3.s -o %t4
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive4.s -o %t5
+# RUN: llvm-ar rcs %tar %t2 %t3 %t4
+# RUN: ld.lld %t %tar %t5 -o %tout
+# RUN: llvm-nm %tout | FileCheck %s
+# RUN: rm -f %tarthin
+# RUN: llvm-ar --format=gnu rcsT %tarthin %t2 %t3 %t4
+# RUN: ld.lld %t %tarthin %t5 -o %tout
+# RUN: llvm-nm %tout | FileCheck %s
+# REQUIRES: x86
+
+# Nothing here. Just needed for the linker to create a undefined _start symbol.
+
+.quad end
+
+.weak foo
+.quad foo
+
+.weak bar
+.quad bar
+
+
+# CHECK:      T _start
+# CHECK-NEXT: T bar
+# CHECK-NEXT: T end
+# CHECK-NEXT: w foo
+
+
+# Test that the hitting the first object file after having a lazy symbol for
+# _start is handled correctly.
+# RUN: ld.lld %tar %t -o %tout
+# RUN: llvm-nm %tout | FileCheck --check-prefix=AR-FIRST %s
+
+# AR-FIRST:      T _start
+# AR-FIRST-NEXT: w bar
+# AR-FIRST-NEXT: T end
+# AR-FIRST-NEXT: w foo
diff --git a/test/ELF/arm-abs32-dyn.s b/test/ELF/arm-abs32-dyn.s
new file mode 100644 (file)
index 0000000..afdf573
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux %s -o %t.o
+
+// Creates a R_ARM_ABS32 relocation against foo and bar, bar has hidden
+// visibility so we expect a R_ARM_RELATIVE
+ .syntax unified
+ .globl foo
+foo:
+ .globl bar
+ .hidden bar
+bar:
+
+ .data
+ .word foo
+ .word bar
+
+// RUN: ld.lld -shared -o %t.so %t.o
+// RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s
+
+// CHECK:      Dynamic Relocations {
+// CHECK-NEXT:   0x1004 R_ARM_RELATIVE
+// CHECK-NEXT:   0x1000 R_ARM_ABS32 foo 0x0
+// CHECK-NEXT: }
+
+// CHECK:      Symbols [
+// CHECK:        Symbol {
+// CHECK:          Name: bar
+// CHECK-NEXT:     Value: 0x1000
+
+// CHECK:        Symbol {
+// CHECK:          Name: foo
+// CHECK-NEXT:     Value: 0x1000
diff --git a/test/ELF/arm-attributes.s b/test/ELF/arm-attributes.s
new file mode 100644 (file)
index 0000000..14517e8
--- /dev/null
@@ -0,0 +1,183 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-attributes1.s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2.o
+
+// RUN: ld.lld %t1.o %t2.o -o %t
+// RUN: llvm-readobj -arm-attributes %t | FileCheck %s
+// RUN: ld.lld %t1.o %t2.o -shared -o %t2
+// RUN: llvm-readobj -arm-attributes %t2 | FileCheck %s
+// RUN: ld.lld %t1.o %t2.o -r -o %t3
+// RUN: llvm-readobj -arm-attributes %t3 | FileCheck %s
+// REQUIRES: arm
+
+// Check that we retain only 1 SHT_ARM_ATTRIBUTES section. At present we do not
+// try and merge or use the contents of SHT_ARM_ATTRIBUTES sections. We just
+// pass the first one through.
+ .text
+ .syntax unified
+ .eabi_attribute        67, "2.09"      @ Tag_conformance
+ .cpu    cortex-a8
+ .eabi_attribute 6, 10   @ Tag_CPU_arch
+ .eabi_attribute 7, 65   @ Tag_CPU_arch_profile
+ .eabi_attribute 8, 1    @ Tag_ARM_ISA_use
+ .eabi_attribute 9, 2    @ Tag_THUMB_ISA_use
+ .fpu    neon
+ .eabi_attribute 15, 1   @ Tag_ABI_PCS_RW_data
+ .eabi_attribute 16, 1   @ Tag_ABI_PCS_RO_data
+ .eabi_attribute 17, 2   @ Tag_ABI_PCS_GOT_use
+ .eabi_attribute 20, 1   @ Tag_ABI_FP_denormal
+ .eabi_attribute 21, 1   @ Tag_ABI_FP_exceptions
+ .eabi_attribute 23, 3   @ Tag_ABI_FP_number_model
+ .eabi_attribute 34, 1   @ Tag_CPU_unaligned_access
+ .eabi_attribute 24, 1   @ Tag_ABI_align_needed
+ .eabi_attribute 25, 1   @ Tag_ABI_align_preserved
+ .eabi_attribute 38, 1   @ Tag_ABI_FP_16bit_format
+ .eabi_attribute 18, 4   @ Tag_ABI_PCS_wchar_t
+ .eabi_attribute 26, 2   @ Tag_ABI_enum_size
+ .eabi_attribute 14, 0   @ Tag_ABI_PCS_R9_use
+ .eabi_attribute 68, 1   @ Tag_Virtualization_use
+ .globl  _start
+ .p2align        2
+ .type   _start,%function
+_start:
+ .globl func
+ bl func
+ bx lr
+
+// CHECK: BuildAttributes {
+// CHECK-NEXT:   FormatVersion: 0x41
+// CHECK-NEXT:   Section 1 {
+// CHECK-NEXT:     SectionLength: 72
+// CHECK-NEXT:     Vendor: aeabi
+// CHECK-NEXT:     Tag: Tag_File (0x1)
+// CHECK-NEXT:     Size: 62
+// CHECK-NEXT:     FileAttributes {
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 67
+// CHECK-NEXT:         TagName: conformance
+// CHECK-NEXT:         Value: 2.09
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 5
+// CHECK-NEXT:         TagName: CPU_name
+// CHECK-NEXT:         Value: cortex-a8
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 6
+// CHECK-NEXT:         Value: 10
+// CHECK-NEXT:         TagName: CPU_arch
+// CHECK-NEXT:         Description: ARM v7
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 7
+// CHECK-NEXT:         Value: 65
+// CHECK-NEXT:         TagName: CPU_arch_profile
+// CHECK-NEXT:         Description: Application
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 8
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ARM_ISA_use
+// CHECK-NEXT:         Description: Permitted
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 9
+// CHECK-NEXT:         Value: 2
+// CHECK-NEXT:         TagName: THUMB_ISA_use
+// CHECK-NEXT:         Description: Thumb-2
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 10
+// CHECK-NEXT:         Value: 3
+// CHECK-NEXT:         TagName: FP_arch
+// CHECK-NEXT:         Description: VFPv3
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 12
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: Advanced_SIMD_arch
+// CHECK-NEXT:         Description: NEONv1
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 14
+// CHECK-NEXT:         Value: 0
+// CHECK-NEXT:         TagName: ABI_PCS_R9_use
+// CHECK-NEXT:         Description: v6
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 15
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ABI_PCS_RW_data
+// CHECK-NEXT:         Description: PC-relative
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 16
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ABI_PCS_RO_data
+// CHECK-NEXT:         Description: PC-relative
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 17
+// CHECK-NEXT:         Value: 2
+// CHECK-NEXT:         TagName: ABI_PCS_GOT_use
+// CHECK-NEXT:         Description: GOT-Indirect
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 18
+// CHECK-NEXT:         Value: 4
+// CHECK-NEXT:         TagName: ABI_PCS_wchar_t
+// CHECK-NEXT:         Description: 4-byte
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 20
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ABI_FP_denormal
+// CHECK-NEXT:         Description: IEEE-754
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 21
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ABI_FP_exceptions
+// CHECK-NEXT:         Description: IEEE-754
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 23
+// CHECK-NEXT:         Value: 3
+// CHECK-NEXT:         TagName: ABI_FP_number_model
+// CHECK-NEXT:         Description: IEEE-754
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 24
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ABI_align_needed
+// CHECK-NEXT:         Description: 8-byte alignment
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 25
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ABI_align_preserved
+// CHECK-NEXT:         Description: 8-byte data alignment
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 26
+// CHECK-NEXT:         Value: 2
+// CHECK-NEXT:         TagName: ABI_enum_size
+// CHECK-NEXT:         Description: Int32
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 34
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: CPU_unaligned_access
+// CHECK-NEXT:         Description: v6-style
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 38
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: ABI_FP_16bit_format
+// CHECK-NEXT:         Description: IEEE-754
+// CHECK-NEXT:       }
+// CHECK-NEXT:       Attribute {
+// CHECK-NEXT:         Tag: 68
+// CHECK-NEXT:         Value: 1
+// CHECK-NEXT:         TagName: Virtualization_use
+// CHECK-NEXT:         Description: TrustZone
+// CHECK-NEXT:       }
diff --git a/test/ELF/arm-blx.s b/test/ELF/arm-blx.s
new file mode 100644 (file)
index 0000000..159eee5
--- /dev/null
@@ -0,0 +1,114 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: echo "SECTIONS { \
+// RUN:          . = 0xb4; \
+// RUN:          .callee1 : { *(.callee_low) } \
+// RUN:          .callee2 : { *(.callee_arm_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .callee3 : { *(.callee_high) } \
+// RUN:          .callee4 : { *(.callee_arm_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s
+// REQUIRES: arm
+
+// Test BLX instruction is chosen for ARM BL/BLX instruction and Thumb callee
+// Using two callees to ensure at least one has 2-byte alignment.
+ .syntax unified
+ .thumb
+ .section .callee_low, "ax",%progbits
+ .align 2
+ .type callee_low,%function
+callee_low:
+ bx lr
+ .type callee_low2, %function
+callee_low2:
+ bx lr
+
+ .section .callee_arm_low, "ax",%progbits
+ .arm
+ .balign 0x100
+ .type callee_arm_low,%function
+ .align 2
+callee_arm_low:
+  bx lr
+
+.section .text, "ax",%progbits
+ .arm
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ bl  callee_low
+ blx callee_low
+ bl  callee_low2
+ blx callee_low2
+ bl  callee_high
+ blx callee_high
+ bl  callee_high2
+ blx callee_high2
+ bl  blx_far
+ blx blx_far2
+// blx to ARM instruction should be written as a BL
+ bl  callee_arm_low
+ blx callee_arm_low
+ bl  callee_arm_high
+ blx callee_arm_high
+ bx lr
+
+ .section .callee_high, "ax",%progbits
+ .balign 0x100
+ .thumb
+ .type callee_high,%function
+callee_high:
+ bx lr
+ .type callee_high2,%function
+callee_high2:
+ bx lr
+
+ .section .callee_arm_high, "ax",%progbits
+ .arm
+ .balign 0x100
+ .type callee_arm_high,%function
+callee_arm_high:
+  bx lr
+
+// CHECK-THUMB: Disassembly of section .callee1:
+// CHECK-THUMB-NEXT: callee_low:
+// CHECK-THUMB-NEXT:    b4:       70 47   bx      lr
+// CHECK-THUMB: callee_low2:
+// CHECK-THUMB-NEXT:    b6:       70 47   bx      lr
+
+// CHECK-ARM: Disassembly of section .callee2:
+// CHECK-ARM-NEXT: callee_arm_low:
+// CHECK-ARM-NEXT:    100:        1e ff 2f e1     bx      lr
+
+// CHECK-ARM: Disassembly of section .caller:
+// CHECK-ARM-NEXT: _start:
+// CHECK-ARM-NEXT:   10000:       2b c0 ff fa     blx     #-65364 <callee_low>
+// CHECK-ARM-NEXT:   10004:       2a c0 ff fa     blx     #-65368 <callee_low>
+// CHECK-ARM-NEXT:   10008:       29 c0 ff fb     blx     #-65370 <callee_low2>
+// CHECK-ARM-NEXT:   1000c:       28 c0 ff fb     blx     #-65374 <callee_low2>
+// CHECK-ARM-NEXT:   10010:       3a 00 00 fa     blx     #232 <callee_high>
+// CHECK-ARM-NEXT:   10014:       39 00 00 fa     blx     #228 <callee_high>
+// CHECK-ARM-NEXT:   10018:       38 00 00 fb     blx     #226 <callee_high2>
+// CHECK-ARM-NEXT:   1001c:       37 00 00 fb     blx     #222 <callee_high2>
+// 10020 + 1FFFFFC + 8 = 0x2010024 = blx_far
+// CHECK-ARM-NEXT:   10020:       ff ff 7f fa     blx     #33554428
+// 10024 + 1FFFFFC + 8 = 0x2010028 = blx_far2
+// CHECK-ARM-NEXT:   10024:       ff ff 7f fa     blx     #33554428
+// CHECK-ARM-NEXT:   10028:       34 c0 ff eb     bl      #-65328 <callee_arm_low>
+// CHECK-ARM-NEXT:   1002c:       33 c0 ff eb     bl      #-65332 <callee_arm_low>
+// CHECK-ARM-NEXT:   10030:       72 00 00 eb     bl      #456 <callee_arm_high>
+// CHECK-ARM-NEXT:   10034:       71 00 00 eb     bl      #452 <callee_arm_high>
+// CHECK-ARM-NEXT:   10038:       1e ff 2f e1     bx      lr
+
+// CHECK-THUMB: Disassembly of section .callee3:
+// CHECK-THUMB: callee_high:
+// CHECK-THUMB-NEXT:    10100:       70 47   bx      lr
+// CHECK-THUMB: callee_high2:
+// CHECK-THUMB-NEXT:    10102:       70 47   bx      lr
+
+// CHECK-ARM: Disassembly of section .callee4:
+// CHECK-NEXT-ARM: callee_arm_high:
+// CHECK-NEXT-ARM:   10200:     1e ff 2f e1     bx      lr
diff --git a/test/ELF/arm-branch-error.s b/test/ELF/arm-branch-error.s
new file mode 100644 (file)
index 0000000..f1a855d
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar
+// RUN: not ld.lld  %t %tfar -o %t2 2>&1 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ // address of too_far symbols are just out of range of ARM branch with
+ // 26-bit immediate field and an addend of -8
+ bl  too_far1
+ b   too_far2
+ beq too_far3
+
+// CHECK: R_ARM_CALL out of range
+// CHECK-NEXT: R_ARM_JUMP24 out of range
+// CHECK-NEXT: R_ARM_JUMP24 out of range
diff --git a/test/ELF/arm-branch.s b/test/ELF/arm-branch.s
new file mode 100644 (file)
index 0000000..986863d
--- /dev/null
@@ -0,0 +1,60 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar
+// RUN: echo "SECTIONS { \
+// RUN:          . = 0xb4; \
+// RUN:          .callee1 : { *(.callee_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .callee2 : { *(.callee_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck  %s
+// REQUIRES: arm
+ .syntax unified
+ .section .callee_low, "ax",%progbits
+ .align 2
+ .type callee_low,%function
+callee_low:
+ bx lr
+
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ bl  callee_low
+ b   callee_low
+ beq callee_low
+ bl  callee_high
+ b   callee_high
+ bne callee_high
+ bl  far
+ b   far
+ bgt far
+ bx lr
+
+ .section .callee_high, "ax",%progbits
+ .align 2
+ .type callee_high,%function
+callee_high:
+ bx lr
+
+// CHECK: Disassembly of section .caller:
+// CHECK-NEXT: _start:
+// S(callee_low) = 0xb4 P = 0x10000 A = -8 = -0xff54 = -65364
+// CHECK-NEXT:   10000:       2b c0 ff eb          bl      #-65364 <callee_low>
+// S(callee_low) = 0xb4 P = 0x10004 A = -8 = -0xff58 = -65368
+// CHECK-NEXT:   10004:       2a c0 ff ea          b       #-65368 <callee_low>
+// S(callee_low) = 0xb4 P = 0x10008 A = -8 = -0xff5c -65372
+// CHECK-NEXT:   10008:       29 c0 ff 0a          beq     #-65372 <callee_low>
+// S(callee_high) = 0x10028 P = 0x1000c A = -8 = 0x14 = 20
+// CHECK-NEXT:   1000c:       05 00 00 eb          bl      #20 <callee_high>
+// S(callee_high) = 0x10028 P = 0x10010 A = -8 = 0x10 = 16
+// CHECK-NEXT:   10010:       04 00 00 ea          b       #16 <callee_high>
+// S(callee_high) = 0x10028 P = 0x10014 A = -8 = 0x0c =12
+// CHECK-NEXT:   10014:       03 00 00 1a          bne     #12 <callee_high>
+// S(far) = 0x201001c P = 0x10018 A = -8 = 0x1fffffc = 33554428
+// CHECK-NEXT:   10018:       ff ff 7f eb          bl      #33554428
+// S(far) = 0x201001c P = 0x1001c A = -8 = 0x1fffff8 = 33554424
+// CHECK-NEXT:   1001c:       fe ff 7f ea          b       #33554424
+// S(far) = 0x201001c P = 0x10020 A = -8 = 0x1fffff4 = 33554420
+// CHECK-NEXT:   10020:       fd ff 7f ca          bgt     #33554420
+// CHECK-NEXT:   10024:       1e ff 2f e1          bx      lr
diff --git a/test/ELF/arm-copy.s b/test/ELF/arm-copy.s
new file mode 100644 (file)
index 0000000..e5ce157
--- /dev/null
@@ -0,0 +1,81 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/relocation-copy-arm.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CODE %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi -section=.rodata %t3 | FileCheck -check-prefix=RODATA %s
+
+// Copy relocations R_ARM_COPY are required for y and z
+ .syntax unified
+ .text
+ .globl _start
+_start:
+ movw r2,:lower16: y
+ movt r2,:upper16: y
+ ldr r3,[pc,#4]
+ ldr r3,[r3,#0]
+ .rodata
+ .word z
+
+// CHECK:     Name: .bss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x13000
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 8
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment: 16
+
+// CHECK: Relocations [
+// CHECK-NEXT:  Section (5) .rel.dyn {
+// CHECK-NEXT:    Relocation {
+// CHECK-NEXT:      Offset: 0x13000
+// CHECK-NEXT:      Type: R_ARM_COPY
+// CHECK-NEXT:      Symbol: y
+// CHECK-NEXT:      Addend: 0x0
+// CHECK-NEXT:    }
+// CHECK-NEXT:    Relocation {
+// CHECK-NEXT:      Offset: 0x13004
+// CHECK-NEXT:      Type: R_ARM_COPY
+// CHECK-NEXT:      Symbol: z
+// CHECK-NEXT:      Addend: 0x0
+// CHECK-NEXT:    }
+// CHECK-NEXT:  }
+
+// CHECK: Symbols [
+// CHECK:     Name: y
+// CHECK-NEXT:    Value: 0x13000
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other:
+// CHECK-NEXT:    Section: .bss
+// CHECK:    Name: z
+// CHECK-NEXT:    Value: 0x13004
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .bss
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// S(y) = 0x13000, A = 0
+// (S + A) & 0x0000ffff = 0x3000 = #12288
+// CODE-NEXT:   11000:  00 20 03 e3    movw    r2, #12288
+// S(y) = 0x13000, A = 0
+// ((S + A) & 0xffff0000) >> 16 = 0x1
+// CODE-NEXT:   11004:       01 20 40 e3    movt    r2, #1
+// CODE-NEXT:   11008:       04 30 9f e5    ldr     r3, [pc, #4]
+// CODE-NEXT:   1100c:       00 30 93 e5    ldr     r3, [r3]
+
+
+// RODATA: Contents of section .rodata:
+// S(z) = 0x13004
+// RODATA-NEXT: 10114 04300100
diff --git a/test/ELF/arm-data-prel.s b/test/ELF/arm-data-prel.s
new file mode 100644 (file)
index 0000000..a8c0c28
--- /dev/null
@@ -0,0 +1,63 @@
+// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o
+// RUN: echo "SECTIONS { \
+// RUN:          .text : { *(.text) } \
+// RUN:          .prel.test : { *(.ARM.exidx) } \
+// RUN:          .prel.test.TEST1 : { *(.ARM.exidx.TEST1) } \
+// RUN:          .TEST1 : { *(.TEST1) } } " > %t.script
+// RUN: ld.lld --script %t.script %t.o -o %t
+// RUN: llvm-readobj -s -sd %t | FileCheck --check-prefix=CHECK %s
+// REQUIRES: arm
+
+// The R_ARM_PREL31 relocation is used in by the .ARM.exidx exception tables
+// bit31 of the place denotes whether the field is an inline table entry
+// (bit31=1) or relocation (bit31=0)
+// The linker must preserve the value of bit31
+
+// This test case is adapted from llvm/test/MC/ARM/eh-compact-pr0.s
+// We use a linker script to place the .ARM.exidx sections in between
+// the code sections so that we can test positive and negative offsets
+ .syntax unified
+
+ .section .TEST1, "ax",%progbits
+ .globl _start
+ .align 2
+ .type  _start,%function
+_start:
+ .fnstart
+ .save   {r11, lr}
+ push    {r11, lr}
+ .setfp  r11, sp
+ mov     r11, sp
+ pop     {r11, lr}
+ mov     pc, lr
+ .fnend
+
+ .section .text, "ax",%progbits
+// The generated .ARM.exidx section will refer to the personality
+// routine __aeabi_unwind_cpp_pr0. Provide a dummy implementation
+// to stop an undefined symbol error
+ .globl __aeabi_unwind_cpp_pr0
+ .align 2
+ .type __aeabi_unwind_cpp_pr0,%function
+__aeabi_unwind_cpp_pr0:
+ .fnstart
+ bx lr
+ .fnend
+
+// The expected value of the exception table is
+// Word0 0 in bit 31, -4 encoded in 31-bit signed offset
+// Word1 Inline table entry EHT Inline Personality Routine #0
+// CHECK:  Name: .prel.test
+// CHECK:  SectionData (
+// CHECK:     0000: FCFFFF7F B0B0B080
+// CHECK:  )
+
+// The expected value of the exception table is
+// Word0 0 in bit 31, +8 encoded in 31-bit signed offset
+// Word1 Inline table entry EHT Inline Personality Routine #0
+// set vsp = r11
+// pop r11, r14
+// CHECK:  Name: .prel.test.TEST1
+// CHECK:  SectionData (
+// CHECK:     0000: 08000000 80849B80
+// CHECK:  )
diff --git a/test/ELF/arm-data-relocs.s b/test/ELF/arm-data-relocs.s
new file mode 100644 (file)
index 0000000..ed23785
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/abs256.s -o %t256.o
+// RUN: ld.lld %t %t256.o -o %t2
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .globl _start
+_start:
+ .section .R_ARM_ABS32POS, "ax",%progbits
+ .word foo + 0x24
+
+// S = 0x100, A = 0x24
+// S + A = 0x124
+// CHECK: Disassembly of section .R_ARM_ABS32POS:
+// CHECK: 11000: 24 01 00 00
+ .section .R_ARM_ABS32NEG, "ax",%progbits
+ .word foo - 0x24
+// S = 0x100, A = -0x24
+// CHECK: Disassembly of section .R_ARM_ABS32NEG:
+// CHECK: 11004: dc 00 00 00
diff --git a/test/ELF/arm-eabi-version.s b/test/ELF/arm-eabi-version.s
new file mode 100644 (file)
index 0000000..727b805
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -file-headers %tout | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .text
+ .globl _start
+_start:
+ bx lr
+
+// CHECK:  Flags [
+// CHECK-NEXT:    0x1000000
+// CHECK-NEXT:    0x4000000
+// CHECK-NEXT:  ]
diff --git a/test/ELF/arm-exidx-canunwind.s b/test/ELF/arm-exidx-canunwind.s
new file mode 100644 (file)
index 0000000..96a7808
--- /dev/null
@@ -0,0 +1,99 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s
+// RUN: llvm-readobj --program-headers --sections %t2 | FileCheck -check-prefix=CHECK-PT %s
+// REQUIRES: arm
+
+// Test that inline unwinding table entries and references to .ARM.extab
+// entries survive the re-ordering of the .ARM.exidx section
+
+ .syntax unified
+ // Will produce an ARM.exidx entry with inline unwinding instructions
+ .section .text.func1, "ax",%progbits
+ .global func1
+func1:
+ .fnstart
+ bx lr
+ .save {r7, lr}
+ .setfp r7, sp, #0
+ .fnend
+
+ // Unwinding instructions for .text2 too large for an inline entry ARM.exidx
+ // entry. A separate .ARM.extab section is created to hold the unwind entries
+ // The .ARM.exidx table entry has a reference to the .ARM.extab section.
+ .section .text.func2, "ax",%progbits
+ .global func2
+func2:
+ .fnstart
+ bx lr
+ .personality __gxx_personality_v0
+ .handlerdata
+ .long 0
+ .section .text.func2
+ .fnend
+
+ // Dummy implementation of personality routines to satisfy reference from
+ // exception tables
+ .section .text.__gcc_personality_v0, "ax", %progbits
+ .global __gxx_personality_v0
+__gxx_personality_v0:
+ bx lr
+
+ .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits
+ .global __aeabi_unwind_cpp_pr0
+__aeabi_unwind_cpp_pr0:
+ bx lr
+
+ .text
+ .global _start
+_start:
+ bl func1
+ bl func2
+ bx lr
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:    11000:       01 00 00 eb     bl      #4 <func1>
+// CHECK-NEXT:    11004:       01 00 00 eb     bl      #4 <func2>
+// CHECK-NEXT:    11008:       1e ff 2f e1     bx      lr
+// CHECK:      func1:
+// CHECK-NEXT:    1100c:       1e ff 2f e1     bx      lr
+// CHECK:      func2:
+// CHECK-NEXT:    11010:       1e ff 2f e1     bx      lr
+// CHECK:      __gxx_personality_v0:
+// CHECK-NEXT:    11014:       1e ff 2f e1     bx      lr
+// CHECK:      __aeabi_unwind_cpp_pr0:
+// CHECK-NEXT:    11018:       1e ff 2f e1     bx      lr
+
+// CHECK-EXIDX: Contents of section .ARM.exidx:
+// 100d4 + f38 = 1100c = func1 (inline unwinding data)
+// 100dc + f34 = 11010 = func2 (100e0 + c = 100ec = .ARM.extab entry)
+// CHECK-EXIDX-NEXT: 100d4 380f0000 08849780 340f0000 0c000000
+// 100e4 + f30 = 11014 = terminate = func2 + sizeof(func2)
+// CHECK-EXIDX-NEXT: 100e4 300f0000 01000000
+// CHECK-EXIDX-NEXT: Contents of section .ARM.extab:
+// 100ec + f28 = 11014 = __gxx_personality_v0
+// CHECK-EXIDX-NEXT: 100ec 280f0000 b0b0b000 00000000
+
+// CHECK-PT:          Name: .ARM.exidx
+// CHECK-PT-NEXT:     Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-PT-NEXT:     Flags [
+// CHECK-PT-NEXT:       SHF_ALLOC
+// CHECK-PT-NEXT:       SHF_LINK_ORDER
+// CHECK-PT-NEXT:     ]
+// CHECK-PT-NEXT:     Address: 0x100D4
+// CHECK-PT-NEXT:     Offset: 0xD4
+// CHECK-PT-NEXT:     Size: 24
+
+// CHECK-PT:          Type: PT_ARM_EXIDX (0x70000001)
+// CHECK-PT-NEXT:     Offset: 0xD4
+// CHECK-PT-NEXT:     VirtualAddress: 0x100D4
+// CHECK-PT-NEXT:     PhysicalAddress: 0x100D4
+// CHECK-PT-NEXT:     FileSize: 24
+// CHECK-PT-NEXT:     MemSize: 24
+// CHECK-PT-NEXT:     Flags [ (0x4)
+// CHECK-PT-NEXT:       PF_R (0x4)
+// CHECK-PT-NEXT:     ]
+// CHECK-PT-NEXT:     Alignment: 4
+// CHECK-PT-NEXT:   }
diff --git a/test/ELF/arm-exidx-gc.s b/test/ELF/arm-exidx-gc.s
new file mode 100644 (file)
index 0000000..1336c25
--- /dev/null
@@ -0,0 +1,124 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 --gc-sections 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s
+// REQUIRES: arm
+
+// Test the behavior of .ARM.exidx sections under garbage collection
+// A .ARM.exidx section is live if it has a relocation to a live executable
+// section.
+// A .ARM.exidx section may have a relocation to a .ARM.extab section, if the
+// .ARM.exidx is live then the .ARM.extab section is live
+
+ .syntax unified
+ .section .text.func1, "ax",%progbits
+ .global func1
+func1:
+ .fnstart
+ bx lr
+ .save {r7, lr}
+ .setfp r7, sp, #0
+ .fnend
+
+ .section .text.unusedfunc1, "ax",%progbits
+ .global unusedfunc1
+unusedfunc1:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ // Unwinding instructions for .text2 too large for an inline entry ARM.exidx
+ // entry. A separate .ARM.extab section is created to hold the unwind entries
+ // The .ARM.exidx table entry has a reference to the .ARM.extab section.
+ .section .text.func2, "ax",%progbits
+ .global func2
+func2:
+ .fnstart
+ bx lr
+ .personality __gxx_personality_v0
+ .handlerdata
+ .section .text.func2
+ .fnend
+
+ // An unused function with a reference to a .ARM.extab section. Both should
+ // be removed by gc.
+ .section .text.unusedfunc2, "ax",%progbits
+ .global unusedfunc2
+unusedfunc2:
+ .fnstart
+ bx lr
+ .personality __gxx_personality_v1
+ .handlerdata
+ .section .text.unusedfunc2
+ .fnend
+
+ // Dummy implementation of personality routines to satisfy reference from
+ // exception tables
+ .section .text.__gcc_personality_v0, "ax", %progbits
+ .global __gxx_personality_v0
+__gxx_personality_v0:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.__gcc_personality_v1, "ax", %progbits
+ .global __gxx_personality_v1
+__gxx_personality_v1:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits
+ .global __aeabi_unwind_cpp_pr0
+__aeabi_unwind_cpp_pr0:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+// Entry point for GC
+ .text
+ .global _start
+_start:
+ bl func1
+ bl func2
+ bx lr
+
+// GC should have only removed unusedfunc1 and unusedfunc2 the personality
+// routines are kept alive by references from live .ARM.exidx and .ARM.extab
+// sections
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:   11000:       01 00 00 eb     bl      #4 <func1>
+// CHECK-NEXT:   11004:       01 00 00 eb     bl      #4 <func2>
+// CHECK-NEXT:   11008:       1e ff 2f e1     bx      lr
+// CHECK: func1:
+// CHECK-NEXT:   1100c:       1e ff 2f e1     bx      lr
+// CHECK: func2:
+// CHECK-NEXT:   11010:       1e ff 2f e1     bx      lr
+// CHECK: __gxx_personality_v0:
+// CHECK-NEXT:   11014:       1e ff 2f e1     bx      lr
+// CHECK: __aeabi_unwind_cpp_pr0:
+// CHECK-NEXT:   11018:       1e ff 2f e1     bx      lr
+
+// GC should have removed table entries for unusedfunc1, unusedfunc2
+// and __gxx_personality_v1
+// CHECK-NOT: unusedfunc1
+// CHECK-NOT: unusedfunc2
+// CHECK-NOT: __gxx_personality_v1
+
+// CHECK-EXIDX: Contents of section .ARM.exidx:
+// 100d4 + f38 = 1100c = func1
+// 100dc + f34 = 11010 = func2 (100e0 + 1c = 100fc = .ARM.extab)
+// CHECK-EXIDX-NEXT: 100d4 380f0000 08849780 340f0000 1c000000
+// 100e4 + f30 = 11014 = __gxx_personality_v0
+// 100ec + f2c = 11018 = __aeabi_unwind_cpp_pr0
+// CHECK-EXIDX-NEXT: 100e4 300f0000 01000000 2c0f0000 01000000
+// 100f4 + f28 = 1101c = __aeabi_unwind_cpp_pr0 + sizeof(__aeabi_unwind_cpp_pr0)
+// CHECK-EXIDX-NEXT: 100f4 280f0000 01000000
+// CHECK-EXIDX-NEXT: Contents of section .ARM.extab:
+// 100fc + f18 = 11014 = __gxx_personality_v0
+// CHECK-EXIDX-NEXT: 100fc 180f0000 b0b0b000
diff --git a/test/ELF/arm-exidx-link.s b/test/ELF/arm-exidx-link.s
new file mode 100644 (file)
index 0000000..50f9812
--- /dev/null
@@ -0,0 +1,25 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+// CHECK:      Name: .ARM.exidx
+// CHECK-NEXT: Type: SHT_ARM_EXIDX
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_LINK_ORDER
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link: [[INDEX:.*]]
+
+// CHECK:      Index: [[INDEX]]
+// CHECK-NEXT: Name: .text
+
+
+        f:
+       .fnstart
+       bx      lr
+       .cantunwind
+       .fnend
diff --git a/test/ELF/arm-exidx-order.s b/test/ELF/arm-exidx-order.s
new file mode 100644 (file)
index 0000000..951c71a
--- /dev/null
@@ -0,0 +1,169 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-exidx-cantunwind.s -o %tcantunwind
+// RUN: ld.lld %t %tcantunwind -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s
+// RUN: llvm-readobj --program-headers --sections %t2 | FileCheck -check-prefix=CHECK-PT %s
+// Use Linker script to place .ARM.exidx in between .text and orphan sections
+// RUN: echo "SECTIONS { \
+// RUN:          .text 0x11000 : { *(.text*) } \
+// RUN:          .ARM.exidx : { *(.ARM.exidx) } } " > %t.script
+// RUN: ld.lld --script %t.script %tcantunwind %t -o %t3 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT-EXIDX %s
+// REQUIRES: arm
+
+// Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set
+// with the sh_link containing the section index of the executable section
+// containing the function it describes. The linker must combine the .ARM.exidx
+// InputSections in the same order that it has combined the executable section,
+// such that the combined .ARM.exidx OutputSection can be used as a binary
+// search table.
+
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+_start:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.f1, "ax", %progbits
+ .globl f1
+f1:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.f2, "ax", %progbits
+ .globl f2
+f2:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+ .globl f3
+f3:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+// Check default no linker script order.
+
+// CHECK: Disassembly of section .text:
+// CHECK: _start:
+// CHECK-NEXT:    11000:       1e ff 2f e1     bx      lr
+// CHECK: f1:
+// CHECK-NEXT:    11004:       1e ff 2f e1     bx      lr
+// CHECK: f2:
+// CHECK-NEXT:    11008:       1e ff 2f e1     bx      lr
+// CHECK: f3:
+// CHECK-NEXT:    1100c:       1e ff 2f e1     bx      lr
+// CHECK: func4:
+// CHECK-NEXT:    11010:       1e ff 2f e1     bx      lr
+// CHECK: func5:
+// CHECK-NEXT:    11014:       1e ff 2f e1     bx      lr
+// CHECK: Disassembly of section .func1:
+// CHECK-NEXT: func1:
+// CHECK-NEXT:    11018:       1e ff 2f e1     bx      lr
+// CHECK: Disassembly of section .func2:
+// CHECK-NEXT: func2:
+// CHECK-NEXT:    1101c:       1e ff 2f e1     bx      lr
+// CHECK: Disassembly of section .func3:
+// CHECK-NEXT: func3:
+// CHECK-NEXT:    11020:       1e ff 2f e1     bx      lr
+
+// Each .ARM.exidx section has two 4 byte fields
+// Field 1 is the 31-bit offset to the function. The top bit is used to
+// indicate whether Field 2 is a pointer or an inline table entry.
+// Field 2 is either a pointer to a .ARM.extab section or an inline table
+// In this example all Field 2 entries are inline can't unwind (0x1)
+// We expect to see the entries in the same order as the functions
+
+// CHECK-EXIDX: Contents of section .ARM.exidx:
+// 100d4 + f2c = 11000 = _start
+// 100dc + f28 = 11004 = f1
+// CHECK-EXIDX-NEXT:       100d4 2c0f0000 01000000 280f0000 01000000
+// 100e4 + f24 = 11008 = f2
+// 100ec + f20 = 1100c = f3
+// CHECK-EXIDX-NEXT:  100e4 240f0000 01000000 200f0000 01000000
+// 100f4 + f1c = 11010 = func4
+// 100fc + f18 = 11014 = func5
+// CHECK-EXIDX-NEXT:  100f4 1c0f0000 01000000 180f0000 01000000
+// 10104 + f14 = 11018 = func1
+// 1010c + f10 = 1101c = func2
+// CHECK-EXIDX-NEXT:  10104 140f0000 01000000 100f0000 01000000
+// 10114 + f0c = 11020 = func3
+// CHECK-EXIDX-NEXT:  10114 0c0f0000 01000000
+
+// Check that PT_ARM_EXIDX program header has been generated that describes
+// the .ARM.exidx output section
+// CHECK-PT:          Name: .ARM.exidx
+// CHECK-PT-NEXT:     Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-PT-NEXT:     Flags [
+// CHECK-PT-NEXT:       SHF_ALLOC
+// CHECK-PT-NEXT:       SHF_LINK_ORDER
+// CHECK-PT-NEXT:     ]
+// CHECK-PT-NEXT:     Address: 0x100D4
+// CHECK-PT-NEXT:     Offset: 0xD4
+// CHECK-PT-NEXT:     Size: 80
+
+// CHECK-PT:          Type: PT_ARM_EXIDX (0x70000001)
+// CHECK-PT-NEXT:     Offset: 0xD4
+// CHECK-PT-NEXT:     VirtualAddress: 0x100D4
+// CHECK-PT-NEXT:     PhysicalAddress: 0x100D4
+// CHECK-PT-NEXT:     FileSize: 80
+// CHECK-PT-NEXT:     MemSize: 80
+// CHECK-PT-NEXT:     Flags [ (0x4)
+// CHECK-PT-NEXT:       PF_R (0x4)
+// CHECK-PT-NEXT:     ]
+// CHECK-PT-NEXT:     Alignment: 4
+// CHECK-PT-NEXT:   }
+
+
+// Check linker script order. The .ARM.exidx section will be inserted after
+// the .text section but before the orphan sections
+
+// CHECK-SCRIPT: Disassembly of section .text:
+// CHECK-SCRIPT-NEXT: func4:
+// CHECK-SCRIPT-NEXT:    11000:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT:      func5:
+// CHECK-SCRIPT-NEXT:    11004:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT:      _start:
+// CHECK-SCRIPT-NEXT:    11008:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT:      f1:
+// CHECK-SCRIPT-NEXT:    1100c:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT:      f2:
+// CHECK-SCRIPT-NEXT:    11010:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT:      f3:
+// CHECK-SCRIPT-NEXT:    11014:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT-NEXT: Disassembly of section .func1:
+// CHECK-SCRIPT-NEXT: func1:
+// CHECK-SCRIPT-NEXT:    11068:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT-NEXT: Disassembly of section .func2:
+// CHECK-SCRIPT-NEXT: func2:
+// CHECK-SCRIPT-NEXT:    1106c:       1e ff 2f e1     bx      lr
+// CHECK-SCRIPT-NEXT: Disassembly of section .func3:
+// CHECK-SCRIPT-NEXT: func3:
+// CHECK-SCRIPT-NEXT:    11070:       1e ff 2f e1     bx      lr
+
+// Check that the .ARM.exidx section is sorted in order as the functions
+// The offset in field 1, is 32-bit so in the binary the most significant bit
+// 11018 - 18 = 11000 func4
+// 11020 - 1c = 11004 func5
+// CHECK-SCRIPT-EXIDX:       11018 e8ffff7f 01000000 e4ffff7f 01000000
+// 11028 - 20 = 11008 _start
+// 11030 - 24 = 1100c f1
+// CHECK-SCRIPT-EXIDX-NEXT:  11028 e0ffff7f 01000000 dcffff7f 01000000
+// 11038 - 28 = 11010 f2
+// 11040 - 2c = 11014 f3
+// CHECK-SCRIPT-EXIDX-NEXT:  11038 d8ffff7f 01000000 d4ffff7f 01000000
+// 11048 + 20 = 11068 func1
+// 11050 + 1c = 1106c func2
+// CHECK-SCRIPT-EXIDX-NEXT:  11048 20000000 01000000 1c000000 01000000
+// 11058 + 18 = 11070 func3
+// 11060 + 14 = 11074 func3 + sizeof(func3)
+// CHECK-SCRIPT-EXIDX-NEXT:  11058 18000000 01000000 14000000 01000000
diff --git a/test/ELF/arm-exidx-output.s b/test/ELF/arm-exidx-output.s
new file mode 100644 (file)
index 0000000..dca43a3
--- /dev/null
@@ -0,0 +1,44 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-readobj -sections %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Check that only a single .ARM.exidx output section is created when
+// there are input sections of the form .ARM.exidx.<section-name>. The
+// assembler creates the .ARM.exidx input sections with the .cantunwind
+// directive
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+_start:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.f1, "ax", %progbits
+ .globl f1
+f1:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.f2, "ax", %progbits
+ .globl f2
+f2:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+// CHECK:         Section {
+// CHECK:         Name: .ARM.exidx
+// CHECK-NEXT:    Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_LINK_ORDER
+// CHECK-NEXT:    ]
+
+// CHECK-NOT:     Name: .ARM.exidx.text.f1
+// CHECK-NOT:     Name: .ARM.exidx.text.f2
diff --git a/test/ELF/arm-exidx-relocatable.s b/test/ELF/arm-exidx-relocatable.s
new file mode 100644 (file)
index 0000000..1b6ee3f
--- /dev/null
@@ -0,0 +1,132 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-exidx-cantunwind.s -o %tcantunwind
+// Check that relocatable link maintains SHF_LINK_ORDER
+// RUN: ld.lld -r %t %tcantunwind -o %t4 2>&1
+// RUN: llvm-readobj -s %t4 | FileCheck %s
+// REQUIRES: arm
+
+// Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set
+// with the sh_link containing the section index of the executable section
+// containing the function it describes. To maintain this property in
+// relocatable links we pass through the .ARM.exidx section, the section it
+// it has a sh_link to, and the associated relocation sections uncombined.
+
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+_start:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.f1, "ax", %progbits
+ .globl f1
+f1:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+ .section .text.f2, "ax", %progbits
+ .globl f2
+f2:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+ .globl f3
+f3:
+ .fnstart
+ bx lr
+ .cantunwind
+ .fnend
+
+// CHECK:         Index: 1
+// CHECK-NEXT:    Name: .text
+
+// CHECK:         Name: .ARM.exidx
+// CHECK-NEXT:    Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-NEXT:    Flags [ (0x82)
+// CHECK-NEXT:      SHF_ALLOC (0x2)
+// CHECK-NEXT:      SHF_LINK_ORDER (0x80)
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 24
+// CHECK-NEXT:    Link: 1
+
+
+// CHECK:         Index: 4
+// CHECK-NEXT:    Name: .text.f1
+
+// CHECK:         Name: .ARM.exidx.text.f1
+// CHECK-NEXT:    Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-NEXT:    Flags [ (0x82)
+// CHECK-NEXT:      SHF_ALLOC (0x2)
+// CHECK-NEXT:      SHF_LINK_ORDER (0x80)
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 8
+// CHECK-NEXT:    Link: 4
+
+
+// CHECK:         Index: 7
+// CHECK-NEXT:    Name: .text.f2
+
+// CHECK:         Name: .ARM.exidx.text.f2
+// CHECK-NEXT:    Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-NEXT:    Flags [ (0x82)
+// CHECK-NEXT:      SHF_ALLOC (0x2)
+// CHECK-NEXT:      SHF_LINK_ORDER (0x80)
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 16
+// CHECK-NEXT:    Link: 7
+
+
+// CHECK:         Index: 10
+// CHECK-NEXT:    Name: .func1
+
+// CHECK:         Name: .ARM.exidx.func1
+// CHECK-NEXT:    Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-NEXT:    Flags [ (0x82)
+// CHECK-NEXT:      SHF_ALLOC (0x2)
+// CHECK-NEXT:      SHF_LINK_ORDER (0x80)
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 8
+// CHECK-NEXT:    Link: 10
+
+
+// CHECK:         Index: 13
+// CHECK-NEXT:    Name: .func2
+
+// CHECK:         Name: .ARM.exidx.func2
+// CHECK-NEXT:    Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-NEXT:    Flags [ (0x82)
+// CHECK-NEXT:      SHF_ALLOC (0x2)
+// CHECK-NEXT:      SHF_LINK_ORDER (0x80)
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 8
+// CHECK-NEXT:    Link: 13
+
+
+// CHECK:         Index: 16
+// CHECK-NEXT:    Name: .func3
+
+// CHECK:         Name: .ARM.exidx.func3
+// CHECK-NEXT:    Type: SHT_ARM_EXIDX (0x70000001)
+// CHECK-NEXT:    Flags [ (0x82)
+// CHECK-NEXT:      SHF_ALLOC (0x2)
+// CHECK-NEXT:      SHF_LINK_ORDER (0x80)
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 8
+// CHECK-NEXT:    Link: 16
diff --git a/test/ELF/arm-exidx-sentinel-norelocatable.s b/test/ELF/arm-exidx-sentinel-norelocatable.s
new file mode 100644 (file)
index 0000000..4a5b64d
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o
+// RUN: ld.lld -r %t.o -o %t
+// REQUIRES: arm
+// RUN: llvm-readobj -s %t | FileCheck %s
+// Check that when doing a relocatable link we don't add a terminating entry
+// to the .ARM.exidx section
+ .syntax unified
+ .text
+_start:
+ .fnstart
+ .cantunwind
+ bx lr
+ .fnend
+
+// Expect 1 table entry of size 8
+// CHECK: Name: .ARM.exidx
+// CHECK: Size: 8
diff --git a/test/ELF/arm-exidx-sentinel-orphan.s b/test/ELF/arm-exidx-sentinel-orphan.s
new file mode 100644 (file)
index 0000000..c054fe9
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// Use Linker script without .ARM.exidx Output Section so it is treated as
+// an orphan. We must still add the sentinel table entry
+// RUN: echo "SECTIONS { \
+// RUN:          .text 0x11000 : { *(.text*) } \
+// RUN:          } " > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// REQUIRES: arm
+
+ .syntax unified
+ .text
+ .global _start
+_start:
+ .fnstart
+ .cantunwind
+ bx lr
+ .fnend
+
+// CHECK: Contents of section .ARM.exidx:
+// 11004 - 4 = 0x11000 = _start
+// 1100c - 8 = 0x11004 = _start + sizeof(_start)
+// CHECK-NEXT: 11004 fcffff7f 01000000 f8ffff7f 01000000
diff --git a/test/ELF/arm-exidx-shared.s b/test/ELF/arm-exidx-shared.s
new file mode 100644 (file)
index 0000000..e067333
--- /dev/null
@@ -0,0 +1,45 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t --shared -o %t2 2>&1
+// RUN: llvm-readobj --relocations %t2 | FileCheck %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXTAB %s
+// REQUIRES: arm
+
+// Check that the relative R_ARM_PREL31 relocation can access a PLT entry
+// for when the personality routine is referenced from a shared library.
+// Also check that the R_ARM_NONE no-op relocation can be used in a shared
+// library.
+ .syntax unified
+// Will produce an ARM.exidx entry with an R_ARM_NONE relocation to
+// __aeabi_unwind_cpp_pr0
+ .section .text.func1, "ax",%progbits
+ .global func1
+func1:
+ .fnstart
+ bx lr
+ .fnend
+
+// Will produce a R_ARM_PREL31 relocation with respect to the PLT entry of
+// __gxx_personality_v0
+ .section .text.func2, "ax",%progbits
+ .global func2
+func2:
+ .fnstart
+ bx lr
+ .personality __gxx_personality_v0
+ .handlerdata
+ .long 0
+ .section .text.func2
+ .fnend
+
+ .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits
+ .global __aeabi_unwind_cpp_pr0
+__aeabi_unwind_cpp_pr0:
+ bx lr
+
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (6) .rel.plt {
+// CHECK-NEXT:     0x200C R_ARM_JUMP_SLOT __gxx_personality_v0
+
+// CHECK-EXTAB: Contents of section .ARM.extab:
+// 014c + 0ed8 = 0x1024 = __gxx_personality_v0(PLT)
+// CHECK-EXTAB-NEXT:  014c d80e0000 b0b0b000 00000000
diff --git a/test/ELF/arm-fpic-got.s b/test/ELF/arm-fpic-got.s
new file mode 100644 (file)
index 0000000..a5f8152
--- /dev/null
@@ -0,0 +1,63 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+// RUN: llvm-readobj -s -symbols %t | FileCheck -check-prefix=SYMBOLS %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s
+
+// Test the R_ARM_GOT_PREL relocation
+ .syntax unified
+ .text
+ .globl _start
+ .align 2
+_start:
+ ldr     r0, .LCPI0_0
+.LPC0_0:
+ ldr     r0, [pc, r0]
+ ldr     r0, [r0]
+ bx      lr
+.LCPI0_0:
+.Ltmp0:
+ // Generate R_ARM_GOT_PREL
+ .long   val(GOT_PREL)-((.LPC0_0+8)-.Ltmp0)
+
+ .data
+ .type   val,%object
+ .globl  val
+ .align  2
+val:
+ .long   10
+ .size   val, 4
+
+// CHECK: Section {
+// CHECK:    Name: .got
+// CHECK-NEXT:    Type: SHT_PROGBITS
+// CHECK-NEXT:      Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x13000
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize:
+
+// SYMBOLS:    Name: val
+// SYMBOLS-NEXT:    Value: 0x12000
+// SYMBOLS-NEXT:    Size: 4
+// SYMBOLS-NEXT:    Binding: Global
+// SYMBOLS-NEXT:    Type: Object
+// SYMBOLS-NEXT:    Other:
+// SYMBOLS-NEXT:    Section: .data
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT:   11000:  08 00 9f e5     ldr     r0, [pc, #8]
+// CODE-NEXT:   11004:  00 00 9f e7     ldr     r0, [pc, r0]
+// CODE-NEXT:   11008:  00 00 90 e5     ldr     r0, [r0]
+// CODE-NEXT:   1100c:  1e ff 2f e1     bx      lr
+// CODE: $d.1:
+// 0x11004 + 0x1ff4 + 8 = 0x13000 = .got
+// CODE-NEXT:   11010:  f4 1f 00 00
diff --git a/test/ELF/arm-gnu-ifunc-nosym.s b/test/ELF/arm-gnu-ifunc-nosym.s
new file mode 100644 (file)
index 0000000..fa79aef
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: arm
+
+// Check that no __rel_iplt_end/__rel_iplt_start
+// appear in symtab if there are no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rel_iplt_end
+// CHECK-NOT: __rel_iplt_start
+// CHECK: ]
+ .syntax unified
+ .text
+ .type foo STT_GNU_IFUNC
+ .globl foo
+foo:
+ bx lr
+
+ .type bar STT_GNU_IFUNC
+ .globl bar
+bar:
+ bx lr
+
+ .globl _start
+_start:
+ bl foo
+ bl bar
diff --git a/test/ELF/arm-gnu-ifunc-plt.s b/test/ELF/arm-gnu-ifunc-plt.s
new file mode 100644 (file)
index 0000000..efcaee1
--- /dev/null
@@ -0,0 +1,101 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %S/Inputs/arm-shared.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -triple=armv7a-linux-gnueabihf -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: arm
+
+// Check that the IRELATIVE relocations are last in the .got
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rel.dyn {
+// CHECK-NEXT:     0x13078 R_ARM_GLOB_DAT bar2 0x0
+// CHECK-NEXT:     0x1307C R_ARM_GLOB_DAT zed2 0x0
+// CHECK-NEXT:     0x13080 R_ARM_IRELATIVE - 0x0
+// CHECK-NEXT:     0x13084 R_ARM_IRELATIVE - 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section (5) .rel.plt {
+// CHECK-NEXT:     0x1200C R_ARM_JUMP_SLOT bar2 0x0
+// CHECK-NEXT:     0x12010 R_ARM_JUMP_SLOT zed2 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Check that the GOT entries refer back to the ifunc resolver
+// GOTPLT: Contents of section .got.plt:
+// GOTPLT-NEXT:  12000 00000000 00000000 00000000 20100100
+// GOTPLT-NEXT:  12010 20100100
+// GOTPLT: Contents of section .got:
+// GOTPLT-NEXT:  13078 00000000 00000000 00100100 04100100
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    11000:       1e ff 2f e1     bx      lr
+// DISASM: bar:
+// DISASM-NEXT:    11004:       1e ff 2f e1     bx      lr
+// DISASM:      _start:
+// DISASM-NEXT:    11008:       14 00 00 eb     bl      #80
+// DISASM-NEXT:    1100c:       17 00 00 eb     bl      #92
+// DISASM:         11010:       00 00 00 00     .word   0x00000000
+// DISASM-NEXT:    11014:       04 00 00 00     .word   0x00000004
+// DISASM:         11018:       05 00 00 eb     bl      #20
+// DISASM-NEXT:    1101c:       08 00 00 eb     bl      #32
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: $a:
+// DISASM-NEXT:    11020:       04 e0 2d e5     str     lr, [sp, #-4]!
+// DISASM-NEXT:    11024:       04 e0 9f e5     ldr     lr, [pc, #4]
+// DISASM-NEXT:    11028:       0e e0 8f e0     add     lr, pc, lr
+// DISASM-NEXT:    1102c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// DISASM: $d:
+// DISASM-NEXT:    11030:       d0 0f 00 00     .word   0x00000fd0
+// DISASM: $a:
+// DISASM-NEXT:    11034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11038:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    1103c:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM: $d:
+// DISASM-NEXT:    11040:       cc 0f 00 00     .word   0x00000fcc
+// DISASM: $a:
+// DISASM-NEXT:    11044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11048:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    1104c:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM: $d:
+// DISASM-NEXT:    11050:       c0 0f 00 00     .word   0x00000fc0
+// Alignment to 16 byte boundary not strictly necessary on ARM, but harmless
+// DISASM-NEXT:    11054:       d4 d4 d4 d4     .word   0xd4d4d4d4
+// DISASM-NEXT:    11058:       d4 d4 d4 d4     .word   0xd4d4d4d4
+// DISASM-NEXT:    1105c:       d4 d4 d4 d4     .word   0xd4d4d4d4
+// DISASM: $a:
+// DISASM-NEXT:    11060:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11064:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    11068:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM: $d:
+// DISASM-NEXT:    1106c:       14 20 00 00     .word   0x00002014
+// DISASM: $a:
+// DISASM-NEXT:    11070:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11074:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    11078:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM: $d:
+// DISASM-NEXT:    1107c:       08 20 00 00     .word   0x00002008
+
+.syntax unified
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ bx lr
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ bx lr
+
+.globl _start
+_start:
+ bl foo
+ bl bar
+ // Create entries in the .got and .rel.dyn so that we don't just have
+ // IRELATIVE
+ .word bar2(got)
+ .word zed2(got)
+ bl bar2
+ bl zed2
diff --git a/test/ELF/arm-gnu-ifunc.s b/test/ELF/arm-gnu-ifunc.s
new file mode 100644 (file)
index 0000000..23c5403
--- /dev/null
@@ -0,0 +1,140 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .text
+ .type foo STT_GNU_IFUNC
+ .globl foo
+foo:
+ bx lr
+
+ .type bar STT_GNU_IFUNC
+ .globl bar
+bar:
+ bx lr
+
+ .globl _start
+_start:
+ bl foo
+ bl bar
+ movw r0,:lower16:__rel_iplt_start
+ movt r0,:upper16:__rel_iplt_start
+ movw r0,:lower16:__rel_iplt_end
+ movt r0,:upper16:__rel_iplt_end
+
+// CHECK: Sections [
+// CHECK:   Section {
+// CHECK:        Section {
+// CHECK:          Name: .rel.dyn
+// CHECK-NEXT:     Type: SHT_REL
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x100F4
+// CHECK-NEXT:     Offset: 0xF4
+// CHECK-NEXT:     Size: 16
+// CHECK:          Name: .plt
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_EXECINSTR
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x11020
+// CHECK-NEXT:     Offset: 0x1020
+// CHECK-NEXT:     Size: 32
+// CHECK:          Name: .got
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x12000
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     Size: 8
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (1) .rel.dyn {
+// CHECK-NEXT:     0x12000 R_ARM_IRELATIVE
+// CHECK-NEXT:     0x12004 R_ARM_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:        Symbol {
+// CHECK:          Name: __rel_iplt_end
+// CHECK-NEXT:     Value: 0x10104
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .rel.dyn
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: __rel_iplt_start
+// CHECK-NEXT:     Value: 0x100F4
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .rel.dyn
+// CHECK-NEXT:   }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: _start
+// CHECK-NEXT:    Value: 0x11008
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other:
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: bar
+// CHECK-NEXT:    Value: 0x11004
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: foo
+// CHECK-NEXT:    Value: 0x11000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    11000:      1e ff 2f e1     bx      lr
+// DISASM:      bar:
+// DISASM-NEXT:    11004:      1e ff 2f e1     bx      lr
+// DISASM:       _start:
+// DISASM-NEXT:    11008:      04 00 00 eb     bl      #16
+// DISASM-NEXT:    1100c:      07 00 00 eb     bl      #28
+// 1 * 65536 + 244 = 0x100f4 __rel_iplt_start
+// DISASM-NEXT:    11010:      f4 00 00 e3     movw    r0, #244
+// DISASM-NEXT:    11014:      01 00 40 e3     movt    r0, #1
+// 1 * 65536 + 260 = 0x10104 __rel_iplt_end
+// DISASM-NEXT:    11018:      04 01 00 e3     movw    r0, #260
+// DISASM-NEXT:    1101c:      01 00 40 e3     movt    r0, #1
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM: $a:
+// DISASM-NEXT:    11020:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11024:       0f c0 8c e0     add     r12, r12, pc
+// 11024 + 8 + fd4 = 0x12000
+// DISASM-NEXT:    11028:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM: $d:
+// DISASM-NEXT:    1102c:       d4 0f 00 00     .word   0x00000fd4
+// DISASM: $a:
+// DISASM-NEXT:    11030:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11034:       0f c0 8c e0     add     r12, r12, pc
+// 11034 + 8 + fc8 = 0x12004        
+// DISASM-NEXT:    11038:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM: $d:
+// DISASM-NEXT:    1103c:       c8 0f 00 00     .word   0x00000fc8
diff --git a/test/ELF/arm-got-relative.s b/test/ELF/arm-got-relative.s
new file mode 100644 (file)
index 0000000..46a3ca9
--- /dev/null
@@ -0,0 +1,53 @@
+// REQUIRES: arm
+// RUN: llvm-mc -position-independent -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -shared -o %t
+// RUN: llvm-readobj -s -symbols -dyn-relocations %t | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s
+ .syntax unified
+ .text
+ .globl _start
+ .align 2
+_start:
+ .type _start, %function
+ ldr r3, .LGOT
+ ldr r2, .LGOT+4
+.LPIC:
+ add r0, pc, r3
+ bx lr
+ .align 2
+.LGOT:
+ // gas implicitly uses (R_ARM_BASE_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC
+ // llvm-mc generates R_ARM_REL32, this will need updating when MC changes
+ .word _GLOBAL_OFFSET_TABLE_ - (.LPIC+8)
+ .word function(GOT)
+
+ .globl function
+ .align 2
+function:
+ .type function, %function
+ bx lr
+
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT:  0x2048 R_ARM_GLOB_DAT function 0x0
+
+// CHECK: Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT:    Value: 0x2048
+// CHECK-NEXT:    Size:
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .got
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT:    1000:        08 30 9f e5    ldr     r3, [pc, #8]
+// CODE-NEXT:    1004:        08 20 9f e5    ldr     r2, [pc, #8]
+// CODE-NEXT:    1008:        03 00 8f e0    add     r0, pc, r3
+// CODE-NEXT:    100c:        1e ff 2f e1    bx      lr
+// CODE:$d.1:
+// (_GLOBAL_OFFSET_TABLE_ = 0x2048) - (0x1008 + 8) 0x1038
+// CODE-NEXT:    1010:        38 10 00 00
+// (Got(function) - GotBase = 0x0
+// CODE-NEXT:    1014:        00 00 00 00
diff --git a/test/ELF/arm-gotoff.s b/test/ELF/arm-gotoff.s
new file mode 100644 (file)
index 0000000..5169f84
--- /dev/null
@@ -0,0 +1,74 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s -r -t %t | FileCheck %s
+// RUN: llvm-objdump -triple=armv7a-linux-gnueabi -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: arm
+
+// Test the R_ARM_GOTOFF32 relocation
+
+// CHECK:      Name: .got
+// CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x12000
+// CHECK-NEXT:    Offset: 0x2000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment:
+
+// CHECK:    Name: .bss
+// CHECK-NEXT:    Type: SHT_NOBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x12000
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 20
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment: 1
+
+// CHECK-NEXT:    EntrySize: 0
+
+// CHECK:       Symbol {
+// CHECK:       Name: bar
+// CHECK-NEXT:    Value: 0x12000
+// CHECK-NEXT:    Size: 10
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .bss
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: obj
+// CHECK-NEXT:    Value: 0x1200A
+// CHECK-NEXT:    Size: 10
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: Object
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .bss
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT :_start:
+// DISASM-NEXT   11000:       1e ff 2f e1     bx      lr
+// Offset 0 from .got = bar
+// DISASM        11004:       00 00 00 00
+// Offset 10 from .got = obj
+// DISASM-NEXT   11008:       0a 00 00 00
+// Offset 15 from .got = obj +5
+// DISASM-NEXT   1100c:       0f 00 00 00
+ .syntax unified
+ .globl _start
+_start:
+ bx lr
+ .word bar(GOTOFF)
+ .word obj(GOTOFF)
+ .word obj(GOTOFF)+5
+ .type bar, %object
+ .comm bar, 10
+ .type obj, %object
+ .comm obj, 10
diff --git a/test/ELF/arm-icf-exidx.s b/test/ELF/arm-icf-exidx.s
new file mode 100644 (file)
index 0000000..6af3028
--- /dev/null
@@ -0,0 +1,33 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 --icf=all
+// RUN: llvm-objdump -s -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+
+ .syntax unified
+ .section        .text.f,"axG",%progbits,f,comdat
+f:
+ .fnstart
+ bx      lr
+ .fnend
+
+ .section        .text.g,"axG",%progbits,g,comdat
+g:
+ .fnstart
+ bx      lr
+ .fnend
+
+ .section .text.h
+ .global __aeabi_unwind_cpp_pr0
+__aeabi_unwind_cpp_pr0:
+ nop
+ bx lr
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: f:
+// CHECK-NEXT:    11000:        1e ff 2f e1     bx      lr
+// CHECK: __aeabi_unwind_cpp_pr0:
+// CHECK-NEXT:    11004:        00 f0 20 e3     nop
+// CHECK-NEXT:    11008:        1e ff 2f e1     bx      lr
+
+// CHECK: Contents of section .ARM.exidx:
+// CHECK-NEXT:  100d4 2c0f0000 b0b0b080 280f0000 01000000
diff --git a/test/ELF/arm-mov-relocs.s b/test/ELF/arm-mov-relocs.s
new file mode 100644 (file)
index 0000000..7e3ce67
--- /dev/null
@@ -0,0 +1,89 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-unknown-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -d %t2 -triple=armv7a-unknown-linux-gnueabi | FileCheck %s
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-unknown-linux-gnueabi %s -o %t3
+// RUN: ld.lld %t3 -o %t4
+// RUN: llvm-objdump -d %t4 -triple=thumbv7a-unknown-linux-gnueabi | FileCheck %s
+// REQUIRES: arm
+
+// Test the R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocations as well as
+// the R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS relocations.
+ .syntax unified
+ .globl _start
+_start:
+ .section .R_ARM_MOVW_ABS_NC, "ax",%progbits
+ movw r0, :lower16:label
+ movw r1, :lower16:label1
+ movw r2, :lower16:label2 + 4
+ movw r3, :lower16:label3
+ movw r4, :lower16:label3 + 4
+// CHECK: Disassembly of section .R_ARM_MOVW_ABS_NC
+// CHECK: movw r0, #0
+// CHECK: movw r1, #4
+// CHECK: movw r2, #12
+// CHECK: movw r3, #65532
+// CHECK: movw r4, #0
+ .section .R_ARM_MOVT_ABS, "ax",%progbits
+ movt r0, :upper16:label
+ movt r1, :upper16:label1
+ movt r2, :upper16:label2 + 4
+ movt r3, :upper16:label3
+ movt r4, :upper16:label3 + 4
+// CHECK: Disassembly of section .R_ARM_MOVT_ABS
+// CHECK: movt r0, #2
+// CHECK: movt r1, #2
+// CHECK: movt r2, #2
+// CHECK: movt r3, #2
+// CHECK: movt r4, #3
+
+.section .R_ARM_MOVW_PREL_NC, "ax",%progbits
+ movw r0, :lower16:label - .
+ movw r1, :lower16:label1 - .
+ movw r2, :lower16:label2 + 4 - .
+ movw r3, :lower16:label3 - .
+ movw r4, :lower16:label3 + 0x103c - .
+// 0x20000 - 0x11028 = :lower16:0xefd8 (61400)
+// CHECK: 11028:  {{.*}}     movw    r0, #61400
+// 0x20004 = 0x1102c = :lower16:0xefd8 (61400)
+// CHECK: 1102c:  {{.*}}     movw    r1, #61400
+// 0x20008 - 0x11030 + 4 = :lower16:0xefdc (61404)
+// CHECK: 11030:  {{.*}}     movw    r2, #61404
+// 0x2fffc - 0x11034 = :lower16:0x1efc8 (61384)
+// CHECK: 11034:  {{.*}}     movw    r3, #61384
+// 0x2fffc - 0x11038 +0x103c :lower16:0x20000 (0)
+// CHECK: 11038:  {{.*}}     movw    r4, #0
+
+.section .R_ARM_MOVT_PREL, "ax",%progbits
+ movt r0, :upper16:label - .
+ movt r1, :upper16:label1 - .
+ movt r2, :upper16:label2 + 0x4 - .
+ movt r3, :upper16:label3 - .
+ movt r4, :upper16:label3 + 0x1050 - .
+// 0x20000 - 0x1103c = :upper16:0xefc4  = 0
+// CHECK: 1103c:  {{.*}}     movt    r0, #0
+// 0x20004 - 0x11040 = :upper16:0xefc0 = 0
+// CHECK: 11040:  {{.*}}     movt    r1, #0
+// 0x20008 - 0x11044 + 4 = :upper16:0xefc8 = 0
+// CHECK: 11044:  {{.*}}     movt    r2, #0
+// 0x2fffc - 0x11048 = :upper16:0x1efb4 = 1
+// CHECK: 11048:  {{.*}}     movt    r3, #1
+// 0x2fffc - 0x1104c + 0x1050 = :upper16:0x20000 = 2
+// CHECK: 1104c:  {{.*}}     movt    r4, #2
+ .section .destination, "aw",%progbits
+ .balign 65536
+// 0x20000
+label:
+ .word 0
+// 0x20004
+label1:
+ .word 1
+// 0x20008
+label2:
+ .word 2
+// Test label3 is immediately below 2^16 alignment boundary
+ .space 65536 - 16
+// 0x2fffc
+label3:
+ .word 3
+// label3 + 4 is on a 2^16 alignment boundary
+ .word 4
diff --git a/test/ELF/arm-pie-relative.s b/test/ELF/arm-pie-relative.s
new file mode 100644 (file)
index 0000000..f965c24
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t --pie -o %t2
+// RUN: llvm-readobj -r %t2 | FileCheck %s
+// RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=GOT
+// REQUIRES: arm
+
+// Test that a R_ARM_GOT_BREL relocation with PIE results in a R_ARM_RELATIVE
+// dynamic relocation
+ .syntax unified
+ .text
+ .global _start
+_start:
+ .word sym(GOT)
+
+ .data
+ .global sym
+sym:
+ .word 0
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rel.dyn {
+// CHECK-NEXT:     0x3058 R_ARM_RELATIVE
+
+// GOT: Contents of section .got:
+// GOT-NEXT:  3058 00200000
diff --git a/test/ELF/arm-plt-reloc.s b/test/ELF/arm-plt-reloc.s
new file mode 100644 (file)
index 0000000..1588f74
--- /dev/null
@@ -0,0 +1,98 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2
+// RUN: ld.lld %t1 %t2 -o %t
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t | FileCheck %s
+// RUN: ld.lld -shared %t1 %t2 -o %t3
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSO %s
+// RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+// REQUIRES: arm
+//
+// Test PLT entry generation
+ .syntax unified
+ .text
+ .align 2
+ .globl _start
+ .type  _start,%function
+_start:
+ b func1
+ bl func2
+ beq func3
+
+// Executable, expect no PLT
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: func1:
+// CHECK-NEXT:   11000:        1e ff 2f e1    bx      lr
+// CHECK: func2:
+// CHECK-NEXT:   11004:        1e ff 2f e1    bx      lr
+// CHECK: func3:
+// CHECK-NEXT:   11008:        1e ff 2f e1    bx      lr
+// CHECK: _start:
+// CHECK-NEXT:   1100c:        fb ff ff ea    b       #-20 <func1>
+// CHECK-NEXT:   11010:        fb ff ff eb    bl      #-20 <func2>
+// CHECK-NEXT:   11014:        fb ff ff 0a    beq     #-20 <func3>
+
+// Expect PLT entries as symbols can be preempted
+// DSO: Disassembly of section .text:
+// DSO-NEXT: func1:
+// DSO-NEXT:    1000:        1e ff 2f e1    bx      lr
+// DSO: func2:
+// DSO-NEXT:    1004:        1e ff 2f e1    bx      lr
+// DSO: func3:
+// DSO-NEXT:    1008:        1e ff 2f e1    bx      lr
+// DSO: _start:
+// S(0x1034) - P(0x100c) + A(-8) = 0x20 = 32
+// DSO-NEXT:    100c:        08 00 00 ea    b       #32
+// S(0x1044) - P(0x1010) + A(-8) = 0x2c = 44
+// DSO-NEXT:    1010:        0b 00 00 eb    bl      #44
+// S(0x1054) - P(0x1014) + A(-8) = 0x38 = 56
+// DSO-NEXT:    1014:        0e 00 00 0a    beq     #56
+
+// DSO: Disassembly of section .plt:
+// DSO-NEXT: $a:
+// DSO-NEXT:     1020:       04 e0 2d e5     str     lr, [sp, #-4]!
+// DSO-NEXT:     1024:       04 e0 9f e5     ldr     lr, [pc, #4]
+// DSO-NEXT:     1028:       0e e0 8f e0     add     lr, pc, lr
+// DSO-NEXT:     102c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// 0x1028 + 8 + 0fd0 = 0x2000
+// DSO: $d:
+// DSO-NEXT:     1030:       d0 0f 00 00     .word   0x00000fd0
+// DSO: $a:
+// DSO-NEXT:     1034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSO-NEXT:     1038:       0f c0 8c e0     add     r12, r12, pc
+// DSO-NEXT:     103c:       00 f0 9c e5     ldr     pc, [r12]
+// 0x1038 + 8 + 0fcc = 0x200c        
+// DSO: $d:
+// DSO-NEXT:     1040:       cc 0f 00 00     .word   0x00000fcc
+// DSO: $a:
+// DSO-NEXT:     1044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSO-NEXT:     1048:       0f c0 8c e0     add     r12, r12, pc
+// DSO-NEXT:     104c:       00 f0 9c e5     ldr     pc, [r12]
+// 0x1048 + 8 + 0fc0 = 0x2010
+// DSO: $d:
+// DSO-NEXT:     1050:       c0 0f 00 00     .word   0x00000fc0
+// DSO: $a:
+// DSO-NEXT:     1054:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSO-NEXT:     1058:       0f c0 8c e0     add     r12, r12, pc
+// DSO-NEXT:     105c:       00 f0 9c e5     ldr     pc, [r12]
+// 0x1058 + 8 + 0fb4 = 0x2014
+// DSO: $d:
+// DSO-NEXT:     1060:       b4 0f 00 00     .word   0x00000fb4
+
+// DSOREL:    Name: .got.plt
+// DSOREL-NEXT:    Type: SHT_PROGBITS
+// DSOREL-NEXT:    Flags [
+// DSOREL-NEXT:      SHF_ALLOC
+// DSOREL-NEXT:      SHF_WRITE
+// DSOREL-NEXT:    ]
+// DSOREL-NEXT:    Address: 0x2000
+// DSOREL-NEXT:    Offset:
+// DSOREL-NEXT:    Size: 24
+// DSOREL-NEXT:    Link:
+// DSOREL-NEXT:    Info:
+// DSOREL-NEXT:    AddressAlignment: 4
+// DSOREL-NEXT:    EntrySize:
+// DSOREL:  Relocations [
+// DSOREL-NEXT:  Section (4) .rel.plt {
+// DSOREL-NEXT:    0x200C R_ARM_JUMP_SLOT func1 0x0
+// DSOREL-NEXT:    0x2010 R_ARM_JUMP_SLOT func2 0x0
+// DSOREL-NEXT:    0x2014 R_ARM_JUMP_SLOT func3 0x0
diff --git a/test/ELF/arm-sbrel32.s b/test/ELF/arm-sbrel32.s
new file mode 100644 (file)
index 0000000..7f12717
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Test the R_ARM_SBREL32 relocation which calculates the offset of the Symbol
+// from the static base. We define the static base to be the address of the
+// segment containing the symbol
+ .text
+ .syntax unified
+
+ .globl _start
+ .p2align       2
+ .type  _start,%function
+_start:
+        .fnstart
+        bx lr
+
+        .long   foo(sbrel)
+        .long   foo2(sbrel)
+        .long   foo3(sbrel)
+        .long   foo4(sbrel)
+// RW segment starts here
+        .data
+        .p2align 4
+foo:    .word 10
+foo2:   .word 20
+
+        .bss
+foo3:   .space 4
+foo4:   .space 4
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:    11000:        1e ff 2f e1     bx      lr
+// CHECK:         11004:        00 00 00 00     .word   0x00000000
+// CHECK-NEXT:    11008:        04 00 00 00     .word   0x00000004
+// CHECK-NEXT:    1100c:        08 00 00 00     .word   0x00000008
+// CHECK-NEXT:    11010:        0c 00 00 00     .word   0x0000000c
diff --git a/test/ELF/arm-static-defines.s b/test/ELF/arm-static-defines.s
new file mode 100644 (file)
index 0000000..0012841
--- /dev/null
@@ -0,0 +1,44 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t --static -o %t2 2>&1
+// RUN: llvm-readobj --symbols %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Check that on ARM we don't get a multiply defined symbol for __tls_get_addr
+// and undefined symbols for references to __exidx_start and __exidx_end
+ .syntax unified
+.section .text
+ .global __tls_get_addr
+__tls_get_addr:
+ bx lr
+
+ .global _start
+ .global __exidx_start
+ .global __exidx_end
+_start:
+ .fnstart
+ bx lr
+ .word __exidx_start
+ .word __exidx_end
+ .cantunwind
+ .fnend
+
+// CHECK:          Name: __exidx_end
+// CHECK-NEXT:     Value: 0x100E4
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .ARM.exidx
+// CHECK:          Name: __exidx_start
+// CHECK-NEXT:     Value: 0x100D4
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   Section: .ARM.exidx
+// CHECK:          Symbol {
+// CHECK-NEXT:     Name: __tls_get_addr
diff --git a/test/ELF/arm-target1.s b/test/ELF/arm-target1.s
new file mode 100644 (file)
index 0000000..e77fa57
--- /dev/null
@@ -0,0 +1,36 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: llvm-readobj -r %t.o | FileCheck %s --check-prefix=RELOC
+// RUN: ld.lld -shared %t.o -o %t2.so --target1-rel
+// RUN: llvm-objdump -t -d %t2.so | FileCheck %s \
+// RUN:   --check-prefix=RELATIVE
+// RUN: not ld.lld -shared %t.o -o %t3.so 2>&1 | FileCheck %s \
+// RUN:   --check-prefix=ABS
+
+// RUN: ld.lld -shared %t.o -o %t2.so --target1-abs --target1-rel
+// RUN: llvm-objdump -t -d %t2.so | FileCheck %s \
+// RUN:   --check-prefix=RELATIVE
+// RUN: not ld.lld -shared %t.o -o %t3.so --target1-rel --target1-abs 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=ABS
+
+// RELOC: Relocations [
+// RELOC:   .rel.text {
+// RELOC:     0x0 R_ARM_TARGET1 patatino 0x0
+// RELOC:   }
+// RELOC: ]
+
+.text
+  .word patatino(target1)
+  patatino:
+        .word 32
+// Force generation of $d.0 as section is not all data
+  nop
+// RELATIVE: Disassembly of section .text:
+// RELATIVE: $d.0:
+// RELATIVE:     1000:       04 00 00 00     .word   0x00000004
+// RELATIVE: SYMBOL TABLE:
+// RELATIVE: 00001004         .text           00000000 patatino
+
+// ABS: can't create dynamic relocation R_ARM_TARGET1 against symbol: patatino
+// ABS: >>> defined in {{.*}}.o
+// ABS: >>> referenced by {{.*}}.o:(.text+0x0)
diff --git a/test/ELF/arm-target2.s b/test/ELF/arm-target2.s
new file mode 100644 (file)
index 0000000..a678f7e
--- /dev/null
@@ -0,0 +1,60 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t 2>&1
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t | FileCheck %s
+// RUN: ld.lld %t.o --target2=got-rel -o %t2 2>&1
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// RUN: ld.lld %t.o --target2=abs -o %t3 2>&1
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-ABS %s
+// RUN: ld.lld %t.o --target2=rel -o %t4 2>&1
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-REL %s
+// REQUIRES: arm
+
+// The R_ARM_TARGET2 is present in .ARM.extab sections. It can be handled as
+// either R_ARM_ABS32, R_ARM_REL32 or R_ARM_GOT_PREL. For ARM linux the default
+// is R_ARM_GOT_PREL. The other two options are primarily used for bare-metal,
+// they can be selected with the --target2=abs or --target2=rel option.
+ .syntax unified
+ .text
+ .globl _start
+ .align 2
+_start:
+ .type function, %function
+ .fnstart
+ bx lr
+ .personality   __gxx_personality_v0
+ .handlerdata
+ .word  _ZTIi(TARGET2)
+ .text
+ .fnend
+ .global __gxx_personality_v0
+ .type function, %function
+__gxx_personality_v0:
+ bx lr
+
+ .rodata
+_ZTIi:  .word 0
+
+// CHECK: Contents of section .ARM.extab:
+// 1011c + 1ee4 = 12000 = .got
+// CHECK-NEXT:  10114 f00e0000 b0b0b000 e41e0000
+
+// CHECK-ABS: Contents of section .ARM.extab:
+// 100f0 = .rodata
+// CHECK-ABS-NEXT: 100d4 300f0000 b0b0b000 f0000100
+
+// CHECK-REL: Contents of section .ARM.extab:
+// 100dc + c = 100e8 = .rodata
+// CHECK-REL-NEXT: 100d4 300f0000 b0b0b000 14000000
+
+// CHECK: Contents of section .rodata:
+// CHECK-NEXT: 10130 00000000
+
+// CHECK-ABS: Contents of section .rodata:
+// CHECK-ABS-NEXT: 100f0 00000000
+
+// CHECK-REL: Contents of section .rodata:
+// CHECK-REL-NEXT: 100f0 00000000
+
+// CHECK: Contents of section .got:
+// 10130 = _ZTIi
+// CHECK-NEXT: 12000 30010100
diff --git a/test/ELF/arm-thumb-blx.s b/test/ELF/arm-thumb-blx.s
new file mode 100644 (file)
index 0000000..d79bef1
--- /dev/null
@@ -0,0 +1,85 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/arm-thumb-blx-targets.s -o %ttarget
+// RUN: echo "SECTIONS { \
+// RUN:          .R_ARM_CALL24_callee1 : { *(.R_ARM_CALL24_callee_low) } \
+// RUN:          .R_ARM_CALL24_callee2 : { *(.R_ARM_CALL24_callee_thumb_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .R_ARM_CALL24_callee3 : { *(.R_ARM_CALL24_callee_high) } \
+// RUN:          .R_ARM_CALL24_callee4 : { *(.R_ARM_CALL24_callee_thumb_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %ttarget -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s
+// REQUIRES: arm
+// Test BLX instruction is chosen for Thumb BL/BLX instruction and ARM callee
+// 2 byte nops are used to test the pc-rounding behaviour. As a BLX from a
+// 2 byte aligned destination is defined as Align(PC,4) + immediate:00
+// FIXME: llvm-mc has problems assembling BLX unless the destination is
+// external. The targets of the BL and BLX instructions are in arm-thumb-blx-target.s
+ .syntax unified
+ .section .text, "ax",%progbits
+ .thumb
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ blx  callee_low
+ nop
+ bl callee_low
+ nop
+ blx  callee_high
+ nop
+ bl callee_high
+ nop
+ blx  blx_far
+ nop
+ bl   blx_far
+ nop
+// Expect BLX to thumb target to be written out as a BL
+ blx   callee_thumb_low
+ nop
+ blx   callee_thumb_high
+ bx lr
+
+// CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee1:
+// CHECK-NEXT-ARM: callee_low:
+// CHECK-NEXT-ARM:      b4:     1e ff 2f e1     bx      lr
+
+// CHECK-THUMB: Disassembly of section .R_ARM_CALL24_callee2:
+// CHECK-NEXT-THUMB: callee_thumb_low:
+// CHECK-NEXT-THUMB:     100:  70 47   bx      lr
+
+// CHECK-THUMB: Disassembly of section .caller:
+// CHECK-THUMB: _start:
+// Align(0x10000,4) - 0xff50 (65360) + 4 = 0xb4 = callee_low
+// CHECK-NEXT-THUMB:   10000:       f0 f7 58 e8     blx     #-65360
+// CHECK-NEXT-THUMB:   10004:       00 bf   nop
+// Align(0x10006,4) - 0xff54 (65364) + 4 = 0xb4 = callee_low
+// CHECK-NEXT-THUMB:   10006:       f0 f7 56 e8     blx     #-65364
+// CHECK-NEXT-THUMB:   1000a:       00 bf   nop
+// Align(0x1000c,4) + 0xf0 (240) + 4 = 0x10100 = callee_high
+// CHECK-NEXT-THUMB:   1000c:   00 f0 78 e8     blx     #240
+// CHECK-NEXT-THUMB:   10010:       00 bf   nop
+// Align(0x10012,4) + 0xec (236) + 4 = 0x10100 = callee_high
+// CHECK-NEXT-THUMB:   10012:       00 f0 76 e8     blx     #236
+// CHECK-NEXT-THUMB:   10016:       00 bf   nop
+// Align(0x10018,4) + 0xfffffc (16777212) = 0x1010018 = blx_far
+// CHECK-NEXT-THUMB:   10018:       ff f3 fe c7     blx     #16777212
+// CHECK-NEXT-THUMB:   1001c:       00 bf   nop
+// Align(0x1001e,4) + 0xfffff8 (16777208) = 0x1010018 = blx_far
+// CHECK-NEXT-THUMB:   1001e:       ff f3 fc c7     blx     #16777208
+// CHECK-NEXT-THUMB:   10022:       00 bf   nop
+// 10024 - 0xff28 (65320) + 4 = 0x100 = callee_thumb_low
+// CHECK-NEXT-THUMB:   10024:       f0 f7 6c f8     bl      #-65320
+// CHECK-NEXT-THUMB:   10028:       00 bf   nop
+// 1002a + 0x1d2 (466) + 4 = 0x10200 = callee_thumb_high
+// CHECK-NEXT-THUMB:   1002a:       00 f0 e9 f8     bl      #466
+// CHECK-NEXT-THUMB:   1002e:       70 47   bx      lr
+
+
+// CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee3:
+// CHECK-NEXT-ARM: callee_high:
+// CHECK-NEXT-ARM:   10100:     1e ff 2f e1     bx      lr
+
+// CHECK: Disassembly of section .R_ARM_CALL24_callee4:
+// CHECK-NEXT-THUMB:callee_thumb_high:
+// CHECK-NEXT-THUMB:   10200:   70 47   bx      lr
diff --git a/test/ELF/arm-thumb-branch-error.s b/test/ELF/arm-thumb-branch-error.s
new file mode 100644 (file)
index 0000000..de6c1bc
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: not ld.lld  %t %tfar -o %t2 2>&1 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ // address of too_far symbols are just out of range of ARM branch with
+ // 26-bit immediate field and an addend of -8
+ bl  too_far1
+ b   too_far2
+ beq.w too_far3
+
+// CHECK: R_ARM_THM_CALL out of range
+// CHECK-NEXT: R_ARM_THM_JUMP24 out of range
+// CHECK-NEXT: R_ARM_THM_JUMP19 out of range
diff --git a/test/ELF/arm-thumb-branch.s b/test/ELF/arm-thumb-branch.s
new file mode 100644 (file)
index 0000000..81bf7a3
--- /dev/null
@@ -0,0 +1,60 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: echo "SECTIONS { \
+// RUN:          . = 0xb4; \
+// RUN:          .callee1 : { *(.callee_low) } \
+// RUN:          .caller : { *(.text) } \
+// RUN:          .callee2 : { *(.callee_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck  %s
+// REQUIRES: arm
+
+ .syntax unified
+ .thumb
+ .section .callee_low, "ax",%progbits
+ .align 2
+ .type callee_low,%function
+callee_low:
+ bx lr
+
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ bl  callee_low
+ b   callee_low
+ beq callee_low
+ bl  callee_high
+ b   callee_high
+ bne callee_high
+ bl  far_uncond
+ b   far_uncond
+ bgt far_cond
+ bx lr
+
+ .section .callee_high, "ax",%progbits
+ .align 2
+ .type callee_high,%function
+callee_high:
+ bx lr
+
+// CHECK: Disassembly of section .callee1:
+// CHECK-NEXT: callee_low:
+// CHECK-NEXT:      b4:       70 47   bx      lr
+// CHECK-NEXT: Disassembly of section .caller:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:   10000:       f0 f7 58 f8     bl      #-65360
+// CHECK-NEXT:   10004:       f0 f7 56 b8     b.w     #-65364
+// CHECK-NEXT:   10008:       30 f4 54 a8     beq.w   #-65368
+// CHECK-NEXT:   1000c:       00 f0 0c f8     bl      #24
+// CHECK-NEXT:   10010:       00 f0 0a b8     b.w     #20
+// CHECK-NEXT:   10014:       40 f0 08 80     bne.w   #16
+// CHECK-NEXT:   10018:       ff f3 ff d7     bl      #16777214
+// CHECK-NEXT:   1001c:       ff f3 fd 97     b.w     #16777210
+// CHECK-NEXT:   10020:       3f f3 ff af     bgt.w   #1048574
+// CHECK-NEXT:   10024:       70 47   bx      lr
+// CHECK-NEXT:   10026:
+// CHECK-NEXT: Disassembly of section .callee2:
+// CHECK-NEXT: callee_high:
+// CHECK-NEXT:   10028:       70 47   bx      lr
diff --git a/test/ELF/arm-thumb-interwork-shared.s b/test/ELF/arm-thumb-interwork-shared.s
new file mode 100644 (file)
index 0000000..8362ae2
--- /dev/null
@@ -0,0 +1,52 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t --shared -o %t.so
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t.so | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s -check-prefix=PLT
+// REQUIRES: arm
+ .syntax unified
+ .global sym1
+ .global elsewhere
+ .weak weakref
+sym1:
+ b.w elsewhere
+ b.w weakref
+
+// Check that we generate a thunk for an undefined symbol called via a plt
+// entry.
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: sym1:
+// CHECK-NEXT: 1000: 00 f0 02 b8 b.w #4 <__ThumbV7PILongThunk_elsewhere>
+// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12 <__ThumbV7PILongThunk_weakref>
+// CHECK: __ThumbV7PILongThunk_elsewhere:
+// CHECK-NEXT:     1008:       40 f2 20 0c     movw    r12, #32
+// CHECK-NEXT:     100c:       c0 f2 00 0c     movt    r12, #0
+// CHECK-NEXT:     1010:       fc 44   add     r12, pc
+// CHECK-NEXT:     1012:       60 47   bx      r12
+
+// CHECK: __ThumbV7PILongThunk_weakref:
+// CHECK-NEXT:     1014:       40 f2 24 0c     movw    r12, #36
+// CHECK-NEXT:     1018:       c0 f2 00 0c     movt    r12, #0
+// CHECK-NEXT:     101c:       fc 44   add     r12, pc
+// CHECK-NEXT:     101e:       60 47   bx      r12
+
+// PLT: Disassembly of section .plt:
+// PLT: $a:
+// PLT-NEXT:     1020:       04 e0 2d e5     str     lr, [sp, #-4]!
+// PLT-NEXT:     1024:       04 e0 9f e5     ldr     lr, [pc, #4]
+// PLT-NEXT:     1028:       0e e0 8f e0     add     lr, pc, lr
+// PLT-NEXT:     102c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// PLT: $d:
+// PLT-NEXT:     1030:       d0 0f 00 00     .word   0x00000fd0
+// PLT: $a:
+// PLT-NEXT:     1034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// PLT-NEXT:     1038:       0f c0 8c e0     add     r12, r12, pc
+// PLT-NEXT:     103c:       00 f0 9c e5     ldr     pc, [r12]
+// PLT: $d:
+// PLT-NEXT:     1040:       cc 0f 00 00     .word   0x00000fcc
+// PLT: $a:
+// PLT-NEXT:     1044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// PLT-NEXT:     1048:       0f c0 8c e0     add     r12, r12, pc
+// PLT-NEXT:     104c:       00 f0 9c e5     ldr     pc, [r12]
+// PLT: $d:
+// PLT-NEXT:     1050:       c0 0f 00 00     .word   0x00000fc0
diff --git a/test/ELF/arm-thumb-interwork-thunk-range.s b/test/ELF/arm-thumb-interwork-thunk-range.s
new file mode 100644 (file)
index 0000000..db674f4
--- /dev/null
@@ -0,0 +1,15 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t -image-base=0x80000000
+
+// Test that when the thunk is at a high address we don't get confused with it
+// being out of range.
+
+.thumb
+.global _start
+_start:
+b.w foo
+
+.arm
+.weak foo
+foo:
diff --git a/test/ELF/arm-thumb-interwork-thunk.s b/test/ELF/arm-thumb-interwork-thunk.s
new file mode 100644 (file)
index 0000000..04755c4
--- /dev/null
@@ -0,0 +1,378 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:       . = SIZEOF_HEADERS; \
+// RUN:       .R_ARM_JUMP24_callee_1 : { *(.R_ARM_JUMP24_callee_low) } \
+// RUN:       .R_ARM_THM_JUMP_callee_1 : { *(.R_ARM_THM_JUMP_callee_low)} \
+// RUN:       .text : { *(.text) } \
+// RUN:       .arm_caller : { *(.arm_caller) } \
+// RUN:       .thumb_caller : { *(.thumb_caller) } \
+// RUN:       .R_ARM_JUMP24_callee_2 : { *(.R_ARM_JUMP24_callee_high) } \
+// RUN:       .R_ARM_THM_JUMP_callee_2 : { *(.R_ARM_THM_JUMP_callee_high) } \
+// RUN:       .got.plt 0x1894 : {  }  } " > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-ABS-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-ABS-ARM %s
+// RUN: ld.lld --script %t.script %t -pie -o %t3 2>&1
+// RUN: ld.lld --script %t.script %t --shared -o %t4 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-PI-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-PI-ARM %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-PI-PLT-THUMB %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-PI-PLT-ARM %s
+// RUN: llvm-readobj -s -r %t4 | FileCheck -check-prefix=CHECK-DSO-REL %s
+// REQUIRES: arm
+
+// Test ARM Thumb Interworking
+// The file is linked and checked 3 times to check the following contexts
+// - Absolute executables, absolute Thunks are used.
+// - Position independent executables, position independent Thunks are used.
+// - Shared object, position independent Thunks to PLT entries are used.
+
+ .syntax unified
+
+// Target Sections for thunks at a lower address than the callers.
+.section .R_ARM_JUMP24_callee_low, "ax", %progbits
+ .thumb
+ .balign 0x1000
+ .globl thumb_callee1
+ .type thumb_callee1, %function
+thumb_callee1:
+ bx lr
+
+// CHECK-THUMB: Disassembly of section .R_ARM_JUMP24_callee_1:
+// CHECK-THUMB: thumb_callee1:
+// CHECK-THUMB: 1000:       70 47   bx
+ .section .R_ARM_THM_JUMP_callee_low, "ax", %progbits
+ .arm
+ .balign 0x100
+ .globl arm_callee1
+ .type arm_callee1, %function
+arm_callee1:
+ bx lr
+// Disassembly of section .R_ARM_THM_JUMP_callee_1:
+// CHECK-ARM: arm_callee1:
+// CHECK-ARM-NEXT: 1100:         1e ff 2f e1     bx      lr
+
+ // Calling sections
+ // At present ARM and Thumb interworking thunks are always added to the calling
+ // section.
+ .section .arm_caller, "ax", %progbits
+ .arm
+ .balign 0x100
+ .globl arm_caller
+ .type arm_caller, %function
+arm_caller:
+ // If target supports BLX and target is in range we don't need an
+ // interworking thunk for a BL or BLX instruction.
+ bl thumb_callee1
+ blx thumb_callee1
+ // A B instruction can't be transformed into a BLX and needs an interworking
+ // thunk
+ b thumb_callee1
+ // As long as the thunk is in range it can be reused
+ b thumb_callee1
+ // There can be more than one thunk associated with a section
+ b thumb_callee2
+ b thumb_callee3
+ // In range ARM targets do not require interworking thunks
+ b arm_callee1
+ beq arm_callee2
+ bne arm_callee3
+ bx lr
+// CHECK-ARM-ABS-ARM: Disassembly of section .arm_caller:
+// CHECK-ARM-ABS-ARM-NEXT: arm_caller:
+// CHECK-ARM-ABS-ARM-NEXT:     1300:       3e ff ff fa     blx     #-776 <thumb_callee1>
+// CHECK-ARM-ABS-ARM-NEXT:     1304:       3d ff ff fa     blx     #-780 <thumb_callee1>
+// CHECK-ARM-ABS-ARM-NEXT:     1308:       06 00 00 ea     b       #24 <__ARMv7ABSLongThunk_thumb_callee1>
+// CHECK-ARM-ABS-ARM-NEXT:     130c:       05 00 00 ea     b       #20 <__ARMv7ABSLongThunk_thumb_callee1>
+// CHECK-ARM-ABS-ARM-NEXT:     1310:       07 00 00 ea     b       #28 <__ARMv7ABSLongThunk_thumb_callee2>
+// CHECK-ARM-ABS-ARM-NEXT:     1314:       09 00 00 ea     b       #36 <__ARMv7ABSLongThunk_thumb_callee3>
+// CHECK-ARM-ABS-ARM-NEXT:     1318:       78 ff ff ea     b       #-544 <arm_callee1>
+// CHECK-ARM-ABS-ARM-NEXT:     131c:       b7 00 00 0a     beq     #732 <arm_callee2>
+// CHECK-ARM-ABS-ARM-NEXT:     1320:       b7 00 00 1a     bne     #732 <arm_callee3>
+// CHECK-ARM-ABS-ARM-NEXT:     1324:       1e ff 2f e1     bx      lr
+// CHECK-ARM-ABS-ARM: __ARMv7ABSLongThunk_thumb_callee1:
+// 0x1001 = thumb_callee1
+// CHECK-ARM-ABS-ARM-NEXT:     1328:       01 c0 01 e3     movw    r12, #4097
+// CHECK-ARM-ABS-ARM-NEXT:     132c:       00 c0 40 e3     movt    r12, #0
+// CHECK-ARM-ABS-ARM-NEXT:     1330:       1c ff 2f e1     bx      r12
+// 0x1501 = thumb_callee2
+// CHECK-ARM-ABS-ARM: __ARMv7ABSLongThunk_thumb_callee2:
+// CHECK-ARM-ABS-ARM-NEXT:     1334:       01 c5 01 e3     movw    r12, #5377
+// CHECK-ARM-ABS-ARM-NEXT:     1338:       00 c0 40 e3     movt    r12, #0
+// CHECK-ARM-ABS-ARM-NEXT:     133c:       1c ff 2f e1     bx      r12
+// 0x1503 = thumb_callee3
+// CHECK-ARM-ABS-ARM: __ARMv7ABSLongThunk_thumb_callee3:
+// CHECK-ARM-ABS-ARM-NEXT:     1340:       03 c5 01 e3     movw    r12, #5379
+// CHECK-ARM-ABS-ARM-NEXT:     1344:       00 c0 40 e3     movt    r12, #0
+// CHECK-ARM-ABS-ARM-NEXT:     1348:       1c ff 2f e1     bx      r12
+
+// CHECK-PI-ARM: Disassembly of section .arm_caller:
+// CHECK-PI-ARM-NEXT: arm_caller:
+// CHECK-PI-ARM-NEXT:     1300:       3e ff ff fa     blx     #-776 <thumb_callee1>
+// CHECK-PI-ARM-NEXT:     1304:       3d ff ff fa     blx     #-780 <thumb_callee1>
+// CHECK-PI-ARM-NEXT:     1308:       06 00 00 ea     b       #24 <__ARMV7PILongThunk_thumb_callee1>
+// CHECK-PI-ARM-NEXT:     130c:       05 00 00 ea     b       #20 <__ARMV7PILongThunk_thumb_callee1>
+// CHECK-PI-ARM-NEXT:     1310:       08 00 00 ea     b       #32 <__ARMV7PILongThunk_thumb_callee2>
+// CHECK-PI-ARM-NEXT:     1314:       0b 00 00 ea     b       #44 <__ARMV7PILongThunk_thumb_callee3>
+// CHECK-PI-ARM-NEXT:     1318:       78 ff ff ea     b       #-544 <arm_callee1>
+// CHECK-PI-ARM-NEXT:     131c:       b7 00 00 0a     beq     #732 <arm_callee2>
+// CHECK-PI-ARM-NEXT:     1320:       b7 00 00 1a     bne     #732 <arm_callee3>
+// CHECK-PI-ARM-NEXT:     1324:       1e ff 2f e1     bx      lr
+// CHECK-PI-ARM: __ARMV7PILongThunk_thumb_callee1:
+// 0x1330 + 8 - 0x337 = 0x1001 = thumb_callee1
+// CHECK-PI-ARM-NEXT:     1328:       c9 cc 0f e3     movw    r12, #64713
+// CHECK-PI-ARM-NEXT:     132c:       ff cf 4f e3     movt    r12, #65535
+// CHECK-PI-ARM-NEXT:     1330:       0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-NEXT:     1334:       1c ff 2f e1     bx      r12
+// CHECK-PI-ARM: __ARMV7PILongThunk_thumb_callee2:
+
+// CHECK-PI-ARM-NEXT:     1338:       b9 c1 00 e3     movw    r12, #441
+// CHECK-PI-ARM-NEXT:     133c:       00 c0 40 e3     movt    r12, #0
+// CHECK-PI-ARM-NEXT:     1340:       0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-NEXT:     1344:       1c ff 2f e1     bx      r12
+// CHECK-PI-ARM: __ARMV7PILongThunk_thumb_callee3:
+// 0x1340 + 8 + 0x1b9 = 0x1501
+// CHECK-PI-ARM-NEXT:     1348:       ab c1 00 e3     movw    r12, #427
+// CHECK-PI-ARM-NEXT:     134c:       00 c0 40 e3     movt    r12, #0
+// CHECK-PI-ARM-NEXT:     1350:       0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-NEXT:     1354:       1c ff 2f e1     bx      r12
+// 1350 + 8 + 0x1ab = 0x1503
+
+// All PLT entries are ARM, no need for interworking thunks
+// CHECK-PI-ARM-PLT: Disassembly of section .arm_caller:
+// CHECK-PI-ARM-PLT-NEXT: arm_caller:
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1300:       37 01 00 eb     bl      #1244
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1304:       36 01 00 eb     bl      #1240
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1308:       35 01 00 ea     b       #1236
+// 0x17e4 PLT(thumb_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    130c:       34 01 00 ea     b       #1232
+// 0x17f4 PLT(thumb_callee2)
+// CHECK-PI-ARM-PLT-NEXT:    1310:       37 01 00 ea     b       #1244
+// 0x1804 PLT(thumb_callee3)
+// CHECK-PI-ARM-PLT-NEXT:    1314:       3a 01 00 ea     b       #1256
+// 0x1814 PLT(arm_callee1)
+// CHECK-PI-ARM-PLT-NEXT:    1318:       3d 01 00 ea     b       #1268
+// 0x1824 PLT(arm_callee2)
+// CHECK-PI-ARM-PLT-NEXT:    131c:       40 01 00 0a     beq     #1280
+// 0x1834 PLT(arm_callee3)
+// CHECK-PI-ARM-PLT-NEXT:    1320:       43 01 00 1a     bne     #1292
+// CHECK-PI-ARM-PLT-NEXT:    1324:       1e ff 2f e1     bx      lr
+
+ .section .thumb_caller, "ax", %progbits
+ .balign 0x100
+ .thumb
+ .globl thumb_caller
+ .type thumb_caller, %function
+thumb_caller:
+ // If target supports BLX and target is in range we don't need an
+ // interworking thunk for a BL or BLX instruction.
+ bl arm_callee1
+ blx arm_callee1
+ // A B instruction can't be transformed into a BLX and needs an interworking
+ // thunk
+ b.w arm_callee1
+ // As long as the thunk is in range it can be reused
+ b.w arm_callee2
+ // There can be more than one thunk associated with a section
+ b.w arm_callee3
+ // Conditional branches also require interworking thunks, they can use the
+ // same interworking thunks.
+ beq.w arm_callee1
+ beq.w arm_callee2
+ bne.w arm_callee3
+// CHECK-ABS-THUMB: Disassembly of section .thumb_caller:
+// CHECK-ABS-THUMB-NEXT: thumb_caller:
+// CHECK-ABS-THUMB-NEXT:     1400:       ff f7 7e ee     blx     #-772
+// CHECK-ABS-THUMB-NEXT:     1404:       ff f7 7c ee     blx     #-776
+// CHECK-ABS-THUMB-NEXT:     1408:       00 f0 0a b8     b.w     #20 <__Thumbv7ABSLongThunk_arm_callee1>
+// CHECK-ABS-THUMB-NEXT:     140c:       00 f0 0d b8     b.w     #26 <__Thumbv7ABSLongThunk_arm_callee2>
+// CHECK-ABS-THUMB-NEXT:     1410:       00 f0 10 b8     b.w     #32 <__Thumbv7ABSLongThunk_arm_callee3>
+// CHECK-ABS-THUMB-NEXT:     1414:       00 f0 04 80     beq.w   #8 <__Thumbv7ABSLongThunk_arm_callee1>
+// CHECK-ABS-THUMB-NEXT:     1418:       00 f0 07 80     beq.w   #14 <__Thumbv7ABSLongThunk_arm_callee2>
+// CHECK-ABS-THUMB-NEXT:     141c:       40 f0 0a 80     bne.w   #20 <__Thumbv7ABSLongThunk_arm_callee3>
+// CHECK-ABS-THUMB: __Thumbv7ABSLongThunk_arm_callee1:
+// 0x1100 = arm_callee1
+// CHECK-ABS-THUMB-NEXT:     1420:       41 f2 00 1c     movw    r12, #4352
+// CHECK-ABS-THUMB-NEXT:     1424:       c0 f2 00 0c     movt    r12, #0
+// CHECK-ABS-THUMB-NEXT:     1428:       60 47   bx      r12
+// CHECK-ABS-THUMB: __Thumbv7ABSLongThunk_arm_callee2:
+// 0x1600 = arm_callee2
+// CHECK-ABS-THUMB-NEXT:     142a:       41 f2 00 6c     movw    r12, #5632
+// CHECK-ABS-THUMB-NEXT:     142e:       c0 f2 00 0c     movt    r12, #0
+// CHECK-ABS-THUMB-NEXT:     1432:       60 47   bx      r12
+// 0x1604 = arm_callee3
+// CHECK-ABS-THUMB: __Thumbv7ABSLongThunk_arm_callee3:
+// CHECK-ABS-THUMB-NEXT:     1434:   41 f2 04 6c     movw    r12, #5636
+// CHECK-ABS-THUMB-NEXT:     1438:       c0 f2 00 0c     movt    r12, #0
+// CHECK-ABS-THUMB-NEXT:     143c:       60 47   bx      r12
+
+// CHECK-PI-THUMB: Disassembly of section .thumb_caller:
+// CHECK-PI-THUMB-NEXT: thumb_caller:
+// CHECK-PI-THUMB-NEXT:     1400:       ff f7 7e ee     blx     #-772
+// CHECK-PI-THUMB-NEXT:     1404:       ff f7 7c ee     blx     #-776
+// CHECK-PI-THUMB-NEXT:     1408:       00 f0 0a b8     b.w     #20 <__ThumbV7PILongThunk_arm_callee1>
+// CHECK-PI-THUMB-NEXT:     140c:       00 f0 0e b8     b.w     #28 <__ThumbV7PILongThunk_arm_callee2>
+// CHECK-PI-THUMB-NEXT:     1410:       00 f0 12 b8     b.w     #36 <__ThumbV7PILongThunk_arm_callee3>
+// CHECK-PI-THUMB-NEXT:     1414:       00 f0 04 80     beq.w   #8 <__ThumbV7PILongThunk_arm_callee1>
+// CHECK-PI-THUMB-NEXT:     1418:       00 f0 08 80     beq.w   #16 <__ThumbV7PILongThunk_arm_callee2>
+// CHECK-PI-THUMB-NEXT:     141c:       40 f0 0c 80     bne.w   #24 <__ThumbV7PILongThunk_arm_callee3>
+// CHECK-PI-THUMB: __ThumbV7PILongThunk_arm_callee1:
+// 0x1428 + 4 - 0x32c = 0x1100 = arm_callee1
+// CHECK-PI-THUMB-NEXT:     1420:       4f f6 d4 4c     movw    r12, #64724
+// CHECK-PI-THUMB-NEXT:     1424:       cf f6 ff 7c     movt    r12, #65535
+// CHECK-PI-THUMB-NEXT:     1428:       fc 44   add     r12, pc
+// CHECK-PI-THUMB-NEXT:     142a:       60 47   bx      r12
+// CHECK-PI-THUMB: __ThumbV7PILongThunk_arm_callee2:
+// 0x1434 + 4 + 0x1c8 = 0x1600 = arm_callee2
+// CHECK-PI-THUMB-NEXT:     142c:       40 f2 c8 1c     movw    r12, #456
+// CHECK-PI-THUMB-NEXT:     1430:       c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-NEXT:     1434:       fc 44   add     r12, pc
+// CHECK-PI-THUMB-NEXT:     1436:       60 47   bx      r12
+// CHECK-PI-THUMB: __ThumbV7PILongThunk_arm_callee3:
+// 0x1440 + 4 + 0x1c0 = 0x1604 = arm_callee3
+// CHECK-PI-THUMB-NEXT:     1438:       40 f2 c0 1c     movw    r12, #448
+// CHECK-PI-THUMB-NEXT:     143c:       c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-NEXT:     1440:       fc 44   add     r12, pc
+// CHECK-PI-THUMB-NEXT:     1442:       60 47   bx      r12
+
+// CHECK-PI-THUMB-PLT: Disassembly of section .arm_caller:
+// CHECK-PI-THUMB-PLT-NEXT: thumb_caller:
+// 0x1400 + 4 + 0x410 = 0x1814 = PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1400:    00 f0 08 ea     blx     #1040
+// 0x1404 + 4 + 0x40c = 0x1814 = PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1404:    00 f0 06 ea     blx     #1036
+// 0x1408 + 4 + 0x14 = 0x1420 = IWV(PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1408:    00 f0 0a b8     b.w     #20
+// 0x140c + 4 + 0x1c = 0x142c = IWV(PLT(arm_callee2)
+// CHECK-PI-THUMB-PLT-NEXT:    140c:    00 f0 0e b8     b.w     #28
+// 0x1410 + 4 + 0x24 = 0x1438 = IWV(PLT(arm_callee3)
+// CHECK-PI-THUMB-PLT-NEXT:    1410:    00 f0 12 b8     b.w     #36
+// 0x1414 + 4 + 8 = 0x1420    = IWV(PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1414:    00 f0 04 80     beq.w   #8
+// 0x1418 + 4 + 0x10 = 0x142c = IWV(PLT(arm_callee2)
+// CHECK-PI-THUMB-PLT-NEXT:    1418:    00 f0 08 80     beq.w   #16
+// 0x141c + 4 + 0x18 = 0x1438 = IWV(PLT(arm_callee3)
+// CHECK-PI-THUMB-PLT-NEXT:    141c:    40 f0 0c 80     bne.w   #24
+// 0x1428 + 4 + 0x3e8 = 0x1814 = PLT(arm_callee1)
+// CHECK-PI-THUMB-PLT-NEXT:    1420:    40 f2 e8 3c     movw    r12, #1000
+// CHECK-PI-THUMB-PLT-NEXT:    1424:    c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-PLT-NEXT:    1428:    fc 44   add     r12, pc
+// CHECK-PI-THUMB-PLT-NEXT:    142a:    60 47   bx      r12
+// 0x1434 + 4 + 0x3ec = 0x1824 = PLT(arm_callee2)
+// CHECK-PI-THUMB-PLT-NEXT:    142c:    40 f2 ec 3c     movw    r12, #1004
+// CHECK-PI-THUMB-PLT-NEXT:    1430:    c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-PLT-NEXT:    1434:    fc 44   add     r12, pc
+// CHECK-PI-THUMB-PLT-NEXT:    1436:    60 47   bx      r12
+// 0x1440 + 4 + 0x3f0 = 0x1834 = PLT(arm_callee3)
+// CHECK-PI-THUMB-PLT-NEXT:    1438:    40 f2 f0 3c     movw    r12, #1008
+// CHECK-PI-THUMB-PLT-NEXT:    143c:    c0 f2 00 0c     movt    r12, #0
+// CHECK-PI-THUMB-PLT-NEXT:    1440:    fc 44   add     r12, pc
+// CHECK-PI-THUMB-PLT-NEXT:    1442:    60 47   bx      r12
+
+// Target Sections for thunks at a higher address than the callers.
+.section .R_ARM_JUMP24_callee_high, "ax", %progbits
+ .thumb
+ .balign 0x100
+ .globl thumb_callee2
+ .type thumb_callee2, %function
+thumb_callee2:
+ bx lr
+
+ .globl thumb_callee3
+ .type thumb_callee3, %function
+thumb_callee3:
+ bx lr
+// CHECK-THUMB:  Disassembly of section .R_ARM_JUMP24_callee_2:
+// CHECK-THUMB-NEXT: thumb_callee2:
+// CHECK-THUMB-NEXT: 1500:       70 47   bx      lr
+// CHECK-THUMB: thumb_callee3:
+// CHECK-THUMB-NEXT: 1502:       70 47   bx      lr
+
+ .section .R_ARM_THM_JUMP_callee_high, "ax", %progbits
+ .arm
+ .balign 0x100
+ .globl arm_callee2
+ .type arm_callee2, %function
+arm_callee2:
+ bx lr
+ .globl arm_callee3
+ .type arm_callee3, %function
+arm_callee3:
+ bx lr
+// CHECK-ARM: Disassembly of section .R_ARM_THM_JUMP_callee_2:
+// CHECK-ARM-NEXT: arm_callee2:
+// CHECK-ARM-NEXT:     1600:     1e ff 2f e1     bx      lr
+// CHECK-ARM: arm_callee3:
+// CHECK-ARM-NEXT:     1604:     1e ff 2f e1     bx      lr
+
+// _start section just calls the arm and thumb calling sections
+ .text
+ .arm
+ .globl _start
+ .balign 0x100
+ .type _start, %function
+_start:
+ bl arm_caller
+ bl thumb_caller
+ bx lr
+
+
+// CHECK-PI-ARM-PLT: Disassembly of section .plt:
+// CHECK-PI-ARM-PLT-NEXT: .plt:
+// CHECK-PI-ARM-PLT-NEXT: 17b0:         04 e0 2d e5     str     lr, [sp, #-4]!
+// CHECK-PI-ARM-PLT-NEXT: 17b4:         04 e0 9f e5     ldr     lr, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17b8:         0e e0 8f e0     add     lr, pc, lr
+// CHECK-PI-ARM-PLT-NEXT: 17bc:         08 f0 be e5     ldr     pc, [lr, #8]!
+// CHECK-PI-ARM-PLT-NEXT: 17c0:         d4 00 00 00
+// 0x17c8 + 8 + 0xd0 = 0x18a0 arm_caller
+// CHECK-PI-ARM-PLT-NEXT: 17c4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17c8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17cc:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 17d0:         d0 00 00 00
+// 0x17d8 + 8 + 0xc4 = 0x18a4 thumb_caller
+// CHECK-PI-ARM-PLT-NEXT: 17d4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17d8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17dc:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 17e0:         c4 00 00 00
+// 0x17e8 + 8 + 0xb8 = 0x18a8 thumb_callee1
+// CHECK-PI-ARM-PLT-NEXT: 17e4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17e8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17ec:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 17f0:         b8 00 00 00
+// 0x17f8 + 8 + 0xac = 0x18ac thumb_callee2
+// CHECK-PI-ARM-PLT-NEXT: 17f4:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 17f8:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 17fc:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1800:         ac 00 00 00
+// 0x1808 + 8 + 0xa0 = 0x18b0 thumb_callee3
+// CHECK-PI-ARM-PLT-NEXT: 1804:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1808:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 180c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1810:         a0 00 00 00
+// 0x1818 + 8 + 0x94 = 0x18b4 arm_callee1
+// CHECK-PI-ARM-PLT-NEXT: 1814:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1818:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 181c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1820:         94 00 00 00
+// 0x1828 + 8 + 0x88 = 0x18b8 arm_callee2
+// CHECK-PI-ARM-PLT-NEXT: 1824:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1828:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 182c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1830:         88 00 00 00
+// 0x1838 + 8 + 0x7c = 0x18bc arm_callee3
+// CHECK-PI-ARM-PLT-NEXT: 1834:         04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK-PI-ARM-PLT-NEXT: 1838:         0f c0 8c e0     add     r12, r12, pc
+// CHECK-PI-ARM-PLT-NEXT: 183c:         00 f0 9c e5     ldr     pc, [r12]
+// CHECK-PI-ARM-PLT-NEXT: 1840:         7c 00 00 00
+
+// CHECK-DSO-REL:      0x18A0 R_ARM_JUMP_SLOT arm_caller
+// CHECK-DSO-REL-NEXT: 0x18A4 R_ARM_JUMP_SLOT thumb_caller
+// CHECK-DSO-REL-NEXT: 0x18A8 R_ARM_JUMP_SLOT thumb_callee1
+// CHECK-DSO-REL-NEXT: 0x18AC R_ARM_JUMP_SLOT thumb_callee2
+// CHECK-DSO-REL-NEXT: 0x18B0 R_ARM_JUMP_SLOT thumb_callee3
+// CHECK-DSO-REL-NEXT: 0x18B4 R_ARM_JUMP_SLOT arm_callee1
+// CHECK-DSO-REL-NEXT: 0x18B8 R_ARM_JUMP_SLOT arm_callee2
+// CHECK-DSO-REL-NEXT: 0x18BC R_ARM_JUMP_SLOT arm_callee3
diff --git a/test/ELF/arm-thumb-narrow-branch-check.s b/test/ELF/arm-thumb-narrow-branch-check.s
new file mode 100644 (file)
index 0000000..82a7164
--- /dev/null
@@ -0,0 +1,73 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:          . = SIZEOF_HEADERS; \
+// RUN:          .R_ARM_PC11_1 : { *(.R_ARM_PC11_1) } \
+// RUN:          .caller : { *(.caller) } \
+// RUN:          .R_ARM_PC11_2 : { *(.R_ARM_PC11_2) } \
+// RUN:          .text : { *(.text) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %S/Inputs/arm-thumb-narrow-branch.o -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Test the R_ARM_PC11 relocation which is used with the narrow encoding of B.N
+// the source of these relocations is a binary file arm-thumb-narrow-branch.o
+// which has been assembled with the GNU assembler as llvm-mc doesn't emit it
+// as the range of +-2048 bytes is too small to be practically useful for out
+// of section branches.
+ .syntax unified
+
+.global callee_low_far
+.type callee_low_far,%function
+callee_low_far = 0x809
+
+ .section .R_ARM_PC11_1,"ax",%progbits
+ .thumb
+ .balign 0x1000
+ .type callee_low,%function
+ .globl callee_low
+callee_low:
+ bx lr
+
+ .text
+ .align 2
+ .thumb
+ .globl _start
+ .type _start, %function
+_start:
+ bl callers
+ bx lr
+
+ .section .R_ARM_PC11_2,"ax",%progbits
+ .thumb
+ .align 2
+ .type callee_high,%function
+ .globl callee_high
+callee_high:
+ bx lr
+
+.global callee_high_far
+.type callee_high_far,%function
+callee_high_far = 0x180d
+
+// CHECK: Disassembly of section .R_ARM_PC11_1:
+// CHECK-NEXT: callee_low:
+// CHECK-NEXT:    1000:       70 47   bx      lr
+// CHECK-NEXT: Disassembly of section .caller:
+// CHECK-NEXT: callers:
+// 1004 - 0x800 (2048) + 4 = 0x808 = callee_low_far
+// CHECK-NEXT:    1004:       00 e4   b       #-2048
+// 1006 - 0xa (10) + 4 = 0x1000 = callee_low
+// CHECK-NEXT:    1006:       fb e7   b       #-10
+// 1008 + 4 + 4 = 0x1010 = callee_high
+// CHECK-NEXT:    1008:       02 e0   b       #4
+// 100a + 0x7fe (2046) + 4 = 0x180c = callee_high_far
+// CHECK-NEXT:    100a:       ff e3   b       #2046
+// CHECK-NEXT:    100c:       70 47   bx      lr
+// CHECK-NEXT:    100e:       00 bf   nop
+// CHECK-NEXT: Disassembly of section .R_ARM_PC11_2:
+// CHECK-NEXT: callee_high:
+// CHECK-NEXT:    1010:       70 47   bx      lr
+// CHECK-NEXT: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:    1014:       ff f7 f6 ff     bl      #-20
+// CHECK-NEXT:    1018:       70 47   bx      lr
diff --git a/test/ELF/arm-thumb-no-undefined-thunk.s b/test/ELF/arm-thumb-no-undefined-thunk.s
new file mode 100644 (file)
index 0000000..775e6fa
--- /dev/null
@@ -0,0 +1,24 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Check that no thunks are created for an undefined weak symbol
+ .syntax unified
+
+.weak target
+
+.section .text.thumb, "ax", %progbits
+ .thumb
+ .global
+_start:
+ bl target
+ b target
+ b.w target
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// 69636 = 0x11004 = next instruction
+// CHECK:         11000: {{.*}} bl      #0
+// CHECK-NEXT:    11004: {{.*}} b.w     #0 <_start+0x8>
+// CHECK-NEXT:    11008: {{.*}} b.w     #0 <_start+0xC>
diff --git a/test/ELF/arm-thumb-plt-reloc.s b/test/ELF/arm-thumb-plt-reloc.s
new file mode 100644 (file)
index 0000000..f9afbb9
--- /dev/null
@@ -0,0 +1,108 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t2
+// RUN: ld.lld %t1 %t2 -o %t
+// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t | FileCheck %s
+// RUN: ld.lld -shared %t1 %t2 -o %t3
+// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOTHUMB %s
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOARM %s
+// RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+// REQUIRES: arm
+//
+// Test PLT entry generation
+ .syntax unified
+ .text
+ .align 2
+ .globl _start
+ .type  _start,%function
+_start:
+// FIXME, interworking is only supported for BL via BLX at the moment, when
+// interworking thunks are available for b.w and b<cond>.w this can be altered
+// to test the different forms of interworking.
+ bl func1
+ bl func2
+ bl func3
+
+// Executable, expect no PLT
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: func1:
+// CHECK-NEXT:   11000: 70 47   bx      lr
+// CHECK: func2:
+// CHECK-NEXT:   11002: 70 47   bx      lr
+// CHECK: func3:
+// CHECK-NEXT:   11004: 70 47   bx      lr
+// CHECK-NEXT:   11006: d4 d4
+// CHECK: _start:
+// 11008 + 4 -12 = 0x11000 = func1
+// CHECK-NEXT:   11008: ff f7 fa ff     bl      #-12
+// 1100c + 4 -14 = 0x11002 = func2
+// CHECK-NEXT:   1100c: ff f7 f9 ff     bl      #-14
+// 11010 + 4 -16 = 0x11004 = func3
+// CHECK-NEXT:   11010: ff f7 f8 ff     bl      #-16
+
+// Expect PLT entries as symbols can be preempted
+// .text is Thumb and .plt is ARM, llvm-objdump can currently only disassemble
+// as ARM or Thumb. Work around by disassembling twice.
+// DSOTHUMB: Disassembly of section .text:
+// DSOTHUMB: func1:
+// DSOTHUMB-NEXT:    1000:       70 47   bx      lr
+// DSOTHUMB: func2:
+// DSOTHUMB-NEXT:    1002:       70 47   bx      lr
+// DSOTHUMB: func3:
+// DSOTHUMB-NEXT:    1004:       70 47   bx      lr
+// DSOTHUMB-NEXT:    1006:       d4 d4
+// DSOTHUMB: _start:
+// 0x1008 + 0x28 + 4 = 0x1034 = PLT func1
+// DSOTHUMB-NEXT:    1008:       00 f0 14 e8     blx     #40
+// 0x100c + 0x34 + 4 = 0x1044 = PLT func2
+// DSOTHUMB-NEXT:    100c:       00 f0 1a e8     blx     #52
+// 0x1010 + 0x40 + 4 = 0x1054 = PLT func3
+// DSOTHUMB-NEXT:    1010:       00 f0 20 e8     blx     #64
+// DSOARM: Disassembly of section .plt:
+// DSOARM-NEXT: $a:
+// DSOARM-NEXT:    1020:       04 e0 2d e5     str     lr, [sp, #-4]!
+// DSOARM-NEXT:    1024:       04 e0 9f e5     ldr     lr, [pc, #4]
+// DSOARM-NEXT:    1028:       0e e0 8f e0     add     lr, pc, lr
+// DSOARM-NEXT:    102c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// DSOARM: $d:
+// DSOARM-NEXT:    1030:       d0 0f 00 00      .word   0x00000fd0
+// 0x1028 + 8 + 0fd0 = 0x2000
+// DSOARM: $a:
+// DSOARM-NEXT:    1034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSOARM-NEXT:    1038:       0f c0 8c e0     add     r12, r12, pc
+// DSOARM-NEXT:    103c:       00 f0 9c e5     ldr     pc, [r12]
+// DSOARM: $d:
+// DSOARM-NEXT:    1040:       cc 0f 00 00     .word   0x00000fcc
+// 0x1038 + 8 + 0fcc = 0x200c
+// DSOARM: $a:
+// DSOARM-NEXT:    1044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSOARM-NEXT:    1048:       0f c0 8c e0     add     r12, r12, pc
+// DSOARM-NEXT:    104c:       00 f0 9c e5     ldr     pc, [r12]
+// DSOARM: $d:
+// DSOARM-NEXT:    1050:       c0 0f 00 00     .word   0x00000fc0
+// 0x1048 + 8 + 0fc0 = 0x2010
+// DSOARM: $a:
+// DSOARM-NEXT:    1054:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DSOARM-NEXT:    1058:       0f c0 8c e0     add     r12, r12, pc
+// DSOARM-NEXT:    105c:       00 f0 9c e5     ldr     pc, [r12]
+// DSOARM: $d:
+// DSOARM-NEXT:    1060:       b4 0f 00 00     .word   0x00000fb4
+// 0x1058 + 8 + 0fb4 = 0x2014
+
+// DSOREL:    Name: .got.plt
+// DSOREL-NEXT:    Type: SHT_PROGBITS
+// DSOREL-NEXT:    Flags [
+// DSOREL-NEXT:      SHF_ALLOC
+// DSOREL-NEXT:      SHF_WRITE
+// DSOREL-NEXT:    ]
+// DSOREL-NEXT:    Address: 0x2000
+// DSOREL-NEXT:    Offset:
+// DSOREL-NEXT:    Size: 24
+// DSOREL-NEXT:    Link:
+// DSOREL-NEXT:    Info:
+// DSOREL-NEXT:    AddressAlignment: 4
+// DSOREL-NEXT:    EntrySize:
+// DSOREL:  Relocations [
+// DSOREL-NEXT:  Section (4) .rel.plt {
+// DSOREL-NEXT:    0x200C R_ARM_JUMP_SLOT func1 0x0
+// DSOREL-NEXT:    0x2010 R_ARM_JUMP_SLOT func2 0x0
+// DSOREL-NEXT:    0x2014 R_ARM_JUMP_SLOT func3 0x0
diff --git a/test/ELF/arm-thumb-thunk-symbols.s b/test/ELF/arm-thumb-thunk-symbols.s
new file mode 100644 (file)
index 0000000..42046f8
--- /dev/null
@@ -0,0 +1,42 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-readobj --symbols %t2 | FileCheck %s
+// RUN: ld.lld --shared %t -o %t3 2>&1
+// RUN: llvm-readobj --symbols %t3 | FileCheck -check-prefix=CHECK-PI %s
+// REQUIRES: arm
+
+// Check that the symbols generated for Thunks have the correct symbol type
+// of STT_FUNC and the correct value of bit 0 (0 for ARM 1 for Thumb)
+ .syntax unified
+ .section .text.thumb, "ax", %progbits
+ .thumb
+ .balign 0x1000
+ .globl thumb_fn
+ .type thumb_fn, %function
+thumb_fn:
+ b.w arm_fn
+
+ .section .text.arm, "ax", %progbits
+ .arm
+ .balign 0x1000
+ .globl arm_fn
+ .type arm_fn, %function
+arm_fn:
+ b thumb_fn
+
+// CHECK:     Name: __Thumbv7ABSLongThunk_arm_fn
+// CHECK-NEXT:     Value: 0x11005
+// CHECK-NEXT:     Size: 10
+// CHECK-NEXT:    Binding: Local (0x0)
+// CHECK-NEXT:    Type: Function (0x2)
+// CHECK:     Name: __ARMv7ABSLongThunk_thumb_fn
+// CHECK-NEXT:     Value: 0x11010
+// CHECK-NEXT:     Size: 12
+// CHECK-NEXT:    Binding: Local (0x0)
+// CHECK-NEXT:    Type: Function (0x2)
+
+// CHECK-PI:     Name: __ThumbV7PILongThunk_arm_fn
+// CHECK-PI-NEXT:     Value: 0x1005
+// CHECK-PI-NEXT:     Size: 12
+// CHECK-PI-NEXT:    Binding: Local (0x0)
+// CHECK-PI-NEXT:    Type: Function (0x2)
diff --git a/test/ELF/arm-thumb-undefined-weak.s b/test/ELF/arm-thumb-undefined-weak.s
new file mode 100644 (file)
index 0000000..7f481b0
--- /dev/null
@@ -0,0 +1,38 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Check that the ARM ABI rules for undefined weak symbols are applied.
+// Branch instructions are resolved to the next instruction. Relative
+// relocations are resolved to the place.
+
+ .syntax unified
+
+ .weak target
+
+ .text
+ .global _start
+_start:
+// R_ARM_THM_JUMP19
+ beq.w target
+// R_ARM_THM_JUMP24
+ b.w target
+// R_ARM_THM_CALL
+ bl target
+// R_ARM_THM_CALL with exchange
+ blx target
+// R_ARM_THM_MOVT_PREL
+ movt r0, :upper16:target - .
+// R_ARM_THM_MOVW_PREL_NC
+ movw r0, :lower16:target - .
+
+// CHECK: Disassembly of section .text:
+// 69636 = 0x11004
+// CHECK:         11000: {{.*}} beq.w   #0 <_start+0x4>
+// CHECK-NEXT:    11004: {{.*}} b.w     #0 <_start+0x8>
+// CHECK-NEXT:    11008: {{.*}} bl      #0
+// blx is transformed into bl so we don't change state
+// CHECK-NEXT:    1100c: {{.*}} bl      #0
+// CHECK-NEXT:    11010: {{.*}} movt    r0, #0
+// CHECK-NEXT:    11014: {{.*}} movw    r0, #0
diff --git a/test/ELF/arm-tls-gd-nonpreemptible.s b/test/ELF/arm-tls-gd-nonpreemptible.s
new file mode 100644 (file)
index 0000000..650c008
--- /dev/null
@@ -0,0 +1,72 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: llvm-objdump -s %t2 | FileCheck %s
+// RUN: ld.lld %t --shared -o %t3.so
+// RUN: llvm-objdump -s %t3.so | FileCheck -check-prefix=CHECK-SHARED %s
+// REQUIRES: arm
+
+// For an executable, we write the module index 1 and the offset into the TLS
+// directly into the GOT. For a shared library we can only write the offset
+// into the TLS directly if the symbol is non-preemptible
+
+ .text
+ .syntax unified
+ .globl __tls_get_addr
+ .type __tls_get_addr,%function
+__tls_get_addr:
+ bx lr
+
+ .globl  _start
+ .p2align        2
+ .type   _start,%function
+func:
+.L0:
+ nop
+.L1:
+ nop
+.L2:
+ nop
+.L3:
+ nop
+ .p2align        2
+// Generate R_ARM_TLS_GD32 relocations
+// These can be resolved at static link time for executables as 1 is always the
+// module index and the offset into tls is known at static link time
+.Lt0: .word   x1(TLSGD) + (. - .L0 - 8)
+.Lt1: .word   x2(TLSGD) + (. - .L1 - 8)
+.Lt2: .word   x3(TLSGD) + (. - .L2 - 8)
+.Lt3: .word   x4(TLSGD) + (. - .L3 - 8)
+ .hidden x1
+ .globl  x1
+ .hidden x2
+ .globl  x2
+ .globl  x3
+ .globl  x4
+
+ .section       .tdata,"awT",%progbits
+ .p2align  2
+.TLSSTART:
+ .type  x1, %object
+x1:
+ .word 10
+ .type  x2, %object
+x2:
+ .word 20
+
+ .section       .tbss,"awT",%nobits
+ .p2align 2
+ .type  x3, %object
+x3:
+ .space 4
+ .type  x4, %object
+x4:
+ .space 4
+
+// CHECK: Contents of section .got:
+// CHECK-NEXT:  12008 01000000 00000000 01000000 04000000
+// CHECK-NEXT:  12018 01000000 08000000 01000000 0c000000
+
+// CHECK-SHARED: Contents of section .got:
+// CHECK-SHARED-NEXT:  2050 00000000 00000000 00000000 04000000
+// CHECK-SHARED-NEXT:  2060 00000000 00000000 00000000 00000000
diff --git a/test/ELF/arm-tls-gd32.s b/test/ELF/arm-tls-gd32.s
new file mode 100644 (file)
index 0000000..206b65d
--- /dev/null
@@ -0,0 +1,106 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
+// REQUIRES: arm
+
+// Test the handling of the global-dynamic TLS model. Dynamic Loader finds
+// module index R_ARM_TLS_DTPMOD32 and the offset within the module
+// R_ARM_TLS_DTPOFF32. One of the variables is hidden which permits relaxation
+// to local dynamic
+
+ .text
+ .syntax unified
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+.L0:
+ nop
+.L1:
+ nop
+.L2:
+ nop
+
+ .p2align        2
+// Generate R_ARM_TLS_GD32 relocations
+// Allocates a pair of GOT entries dynamically relocated by R_ARM_TLS_DTPMOD32
+// and R_ARM_TLS_DTPOFF32 respectively. The literal contains the offset of the
+// first GOT entry from the place
+.Lt0: .word   x(TLSGD) + (. - .L0 - 8)
+.Lt1: .word   y(TLSGD) + (. - .L1 - 8)
+.Lt2: .word   z(TLSGD) + (. - .L2 - 8)
+
+// __thread int x = 10
+// __thread int y;
+// __thread int z __attribute((visibility("hidden")))
+
+ .hidden z
+ .globl  z
+ .globl  y
+ .globl  x
+
+ .section       .tbss,"awT",%nobits
+ .p2align  2
+.TLSSTART:
+ .type  z, %object
+z:
+ .space 4
+ .type  y, %object
+y:
+ .space 4
+ .section       .tdata,"awT",%progbits
+ .p2align 2
+ .type  x, %object
+x:
+ .word  10
+
+// SEC:      Name: .tdata
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT:  ]
+// SEC-NEXT: Address: 0x2000
+// SEC:      Size: 4
+// SEC:      Name: .tbss
+// SEC-NEXT: Type: SHT_NOBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x2004
+// SEC:      Size: 8
+
+// SEC:      Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x204C
+// SEC:      Size: 24
+
+// SEC: Dynamic Relocations {
+// SEC-NEXT: 0x205C R_ARM_TLS_DTPMOD32 -
+// SEC-NEXT: 0x204C R_ARM_TLS_DTPMOD32 x
+// SEC-NEXT: 0x2050 R_ARM_TLS_DTPOFF32 x
+// SEC-NEXT: 0x2054 R_ARM_TLS_DTPMOD32 y
+// SEC-NEXT: 0x2058 R_ARM_TLS_DTPOFF32 y
+
+
+// CHECK: Disassembly
+// CHECK-NEXT: func:
+// CHECK-NEXT:    1000:      00 f0 20 e3     nop
+// CHECK-NEXT:    1004:      00 f0 20 e3     nop
+// CHECK-NEXT:    1008:      00 f0 20 e3     nop
+
+// (0x204c - 0x100c) + (0x100c - 0x1000 - 8) = 0x1044
+// CHECK:    100c:     44 10 00 00
+// (0x2054 - 0x1010) + (0x1010 - 0x1004 - 8) = 0x1048
+// CHECK-NEXT:    1010:        48 10 00 00
+// (0x205c - 0x1014) + (0x1014 - 0x1008 - 8) = 0x104c
+// CHECK-NEXT:    1014:        4c 10 00 00
+
diff --git a/test/ELF/arm-tls-ie32.s b/test/ELF/arm-tls-ie32.s
new file mode 100644 (file)
index 0000000..48120fa
--- /dev/null
@@ -0,0 +1,96 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
+// REQUIRES: arm
+
+// Test the handling of the initial-exec TLS model. Relative location within
+// static TLS is a run-time constant computed by dynamic loader as a result
+// of the R_ARM_TLS_TPOFF32 relocation.
+
+ .syntax unified
+ .arm
+ .globl func
+ .type  func,%function
+ .p2align 2
+func:
+.L0:
+ nop
+.L1:
+ nop
+.L2:
+ nop
+
+ .p2align 2
+// Generate R_ARM_TLS_IE32 static relocations
+// Allocates a GOT entry dynamically relocated by R_ARM_TLS_TPOFF32
+// literal contains the offset of the GOT entry from the place
+.Lt0: .word  x(gottpoff) + (. - .L0 - 8)
+.Lt1: .word  y(gottpoff) + (. - .L1 - 8)
+.Lt2: .word  .TLSSTART(gottpoff) + (. - .L2 - 8)
+
+// __thread int x = 10
+// __thread int y;
+// __thread int z __attribute((visibility("hidden")))
+ .hidden z
+ .globl  z
+ .globl  y
+ .globl  x
+
+ .section       .tbss,"awT",%nobits
+ .p2align  2
+.TLSSTART:
+ .type  z, %object
+z:
+ .space 4
+ .type  y, %object
+y:
+ .space 4
+ .section       .tdata,"awT",%progbits
+ .p2align 2
+ .type  x, %object
+x:
+ .word  10
+
+// SEC:      Name: .tdata
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC:      Size: 4
+// SEC:      Name: .tbss
+// SEC-NEXT: Type: SHT_NOBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC: Size: 8
+
+// SEC:      Name: .got
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:    SHF_ALLOC
+// SEC-NEXT:    SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x204C
+// SEC:      Size: 12
+
+
+// SEC: Dynamic Relocations {
+// SEC:  0x2054 R_ARM_TLS_TPOFF32
+// SEC:  0x204C R_ARM_TLS_TPOFF32 x
+// SEC:  0x2050 R_ARM_TLS_TPOFF32 y
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: func:
+// CHECK-NEXT:    1000: 00 f0 20 e3     nop
+// CHECK-NEXT:    1004: 00 f0 20 e3     nop
+// CHECK-NEXT:    1008: 00 f0 20 e3     nop
+
+// (0x204c - 0x100c) + (0x100c - 0x1000 - 8) = 0x1044
+// CHECK:         100c: 44 10 00 00
+// (0x2050 - 0x1010) + (0x1010 - 0x1004 - 8) = 0x1044
+// CHECK-NEXT:    1010: 44 10 00 00
+// (0x2054 - 0x1014) + (0x1014 - 0x1008 - 8) = 0x1044
+// CHECK-NEXT:    1014: 44 10 00 00
diff --git a/test/ELF/arm-tls-ldm32.s b/test/ELF/arm-tls-ldm32.s
new file mode 100644 (file)
index 0000000..47e8791
--- /dev/null
@@ -0,0 +1,73 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s
+// REQUIRES: arm
+
+// Test the handling of the local-dynamic TLS model. Dynamic loader finds
+// module index R_ARM_TLS_DTPMOD32. The offset in the next GOT slot is 0
+// The R_ARM_TLS_LDO is the offset of the variable within the TLS block.
+ .global __tls_get_addr
+ .text
+ .p2align  2
+ .global _start
+ .syntax unified
+ .arm
+ .type   _start, %function
+_start:
+.L0:
+ nop
+
+ .word   x(tlsldm) + (. - .L0 - 8)
+ .word   x(tlsldo)
+ .word   y(tlsldo)
+
+ .section        .tbss,"awT",%nobits
+ .p2align  2
+ .type   y, %object
+y:
+ .space  4
+ .section        .tdata,"awT",%progbits
+ .p2align  2
+ .type   x, %object
+x:
+ .word   10
+
+// SEC:      Name: .tdata
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x2000
+// SEC:    Size: 4
+// SEC:    Name: .tbss
+// SEC-NEXT: Type: SHT_NOBITS (0x8)
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x2004
+// SEC:      Size: 4
+
+// SEC: Dynamic Relocations {
+// SEC-NEXT:  0x204C R_ARM_TLS_DTPMOD32 - 0x0
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT: 1000:       00 f0 20 e3     nop
+
+// (0x204c - 0x1004) + (0x1004 - 0x1000 - 8) = 0x1044
+// CHECK:      1004:       44 10 00 00
+// CHECK-NEXT: 1008:       00 00 00 00
+// CHECK-NEXT: 100c:       04 00 00 00
+
+// CHECK-EXE: Disassembly of section .text:
+// CHECK-NEXT-EXE: _start:
+// CHECK-NEXT-EXE:   11000:       00 f0 20 e3     nop
+
+// CHECK-EXE:   11004:       fc 0f 00 00
+// CHECK-EXE:   11008:       00 00 00 00
+// CHECK-EXE:   1100c:       04 00 00 00
diff --git a/test/ELF/arm-tls-le32.s b/test/ELF/arm-tls-le32.s
new file mode 100644 (file)
index 0000000..4d42a06
--- /dev/null
@@ -0,0 +1,77 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t | FileCheck %s
+// REQUIRES: arm
+
+// Test the handling of the local exec TLS model. TLS can be resolved
+// statically for an application. The code sequences assume a thread pointer
+// in r9
+
+ .text
+ .syntax unified
+ .globl  _start
+ .p2align        2
+ .type   _start,%function
+_start:
+ .p2align        2
+// Generate R_ARM_TLS_LE32 relocations. These resolve statically to the offset
+// of the variable from the thread pointer
+.Lt0: .word   x(TPOFF)
+.Lt1: .word   y(TPOFF)
+.Lt2: .word   z(TPOFF)
+
+// __thread int x = 10
+// __thread int y;
+// __thread int z __attribute((visibility("hidden")))
+
+ .hidden z
+ .globl  z
+ .globl  y
+ .globl  x
+
+ .section       .tbss,"awT",%nobits
+ .p2align  2
+.TLSSTART:
+ .type  z, %object
+z:
+ .space 4
+ .type  y, %object
+y:
+ .space 4
+ .section       .tdata,"awT",%progbits
+ .p2align 2
+ .type  x, %object
+x:
+ .word  10
+
+// SEC:      Name: .tdata
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT:  ]
+// SEC-NEXT: Address: 0x12000
+// SEC:      Size: 4
+// SEC:      Name: .tbss
+// SEC-NEXT: Type: SHT_NOBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_TLS
+// SEC-NEXT:   SHF_WRITE
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x12004
+// SEC:      Size: 8
+
+// SEC: Dynamic Relocations {
+// SEC-NEXT: }
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// offset of x from Thread pointer = (TcbSize + 0x0 = 0x8)
+// CHECK-NEXT:   11000:         08 00 00 00
+// offset of z from Thread pointer = (TcbSize + 0x8 = 0x10)
+// CHECK-NEXT:   11004:         10 00 00 00
+// offset of y from Thread pointer = (TcbSize + 0x4 = 0xc)
+// CHECK-NEXT:   11008:         0c 00 00 00
diff --git a/test/ELF/arm-tls-norelax-gd-ie.s b/test/ELF/arm-tls-norelax-gd-ie.s
new file mode 100644 (file)
index 0000000..2617089
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// RUN: ld.lld %t1 --shared -o %t1.so
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t1.so %t.o -o %t
+// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s
+// REQUIRES: arm
+
+// This tls global-dynamic sequence is with respect to a preemptible symbol but
+// is in an application so a relaxation to Initial Exec would normally be
+// possible. This would result in an assertion failure on ARM as the
+// relaxation functions can't be implemented on ARM. Check that the sequence
+// is handled as global dynamic
+
+ .text
+ .syntax unified
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+.L0:
+ .globl __tls_get_addr
+ bl __tls_get_addr
+ bx lr
+ .p2align 2
+ .Lt0: .word   y(TLSGD) + (. - .L0 - 8)
+
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT:   0x13078 R_ARM_TLS_DTPMOD32 y
+// CHECK-NEXT:   0x1307C R_ARM_TLS_DTPOFF32 y
+// CHECK-NEXT:   0x1200C R_ARM_JUMP_SLOT __tls_get_addr
diff --git a/test/ELF/arm-tls-norelax-gd-le.s b/test/ELF/arm-tls-norelax-gd-le.s
new file mode 100644 (file)
index 0000000..41df724
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// RUN: ld.lld %t1 --shared -o %t1.so
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t1.so %t.o -o %t
+// RUN: llvm-objdump -s %t | FileCheck %s
+// REQUIRES: arm
+
+// This tls global-dynamic sequence is with respect to a non-preemptible
+// symbol in an application so a relaxation to Local Exec would normally be
+// possible. This would result in an assertion failure on ARM as the
+// relaxation functions can't be implemented on ARM. Check that the sequence
+// is handled as global dynamic
+
+ .text
+ .syntax unified
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+.L0:
+ .globl __tls_get_addr
+ bl __tls_get_addr
+ bx lr
+ .p2align 2
+ .Lt0: .word   x(TLSGD) + (. - .L0 - 8)
+
+ .globl  x
+.section       .tbss,"awT",%nobits
+ .p2align  2
+x:
+ .space 4
+ .type  x, %object
+
+// CHECK:       Contents of section .got:
+// Module index is always 1 for executable
+// CHECK-NEXT:  13060 01000000 00000000
+
diff --git a/test/ELF/arm-tls-norelax-ie-le.s b/test/ELF/arm-tls-norelax-ie-le.s
new file mode 100644 (file)
index 0000000..e8c528b
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// RUN: ld.lld %t1 --shared -o %t1.so
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t1.so %t.o -o %t
+// RUN: llvm-objdump -s -triple=armv7a-linux-gnueabi %t | FileCheck %s
+// REQUIRES: arm
+
+// This tls Initial Exec sequence is with respect to a non-preemptible symbol
+// so a relaxation would normally be possible. This would result in an assertion
+// failure on ARM as the relaxation functions can't be implemented on ARM.
+// Check that the sequence is handled as initial exec
+ .text
+ .syntax unified
+ .globl  func
+ .p2align        2
+ .type   func,%function
+func:
+.L0:
+ .globl __tls_get_addr
+ bl __tls_get_addr
+.L1:
+ bx lr
+ .p2align 2
+ .Lt0: .word  x1(gottpoff) + (. - .L0 - 8)
+ .Lt1: .word  x2(gottpoff) + (. - .L1 - 8)
+
+ .globl  x1
+ .section       .trw,"awT",%progbits
+ .p2align  2
+x1:
+ .word 0x1
+ .globl x2
+ .section       .tbss,"awT",%nobits
+ .type  x1, %object
+x2:
+ .space 4
+ .type x2, %object
+
+// CHECK: Contents of section .got:
+// x1 at offset 8 from TP, x2 at offset c from TP. Offsets include TCB size of 8
+// CHECK-NEXT: 13064 08000000 0c000000
diff --git a/test/ELF/arm-tls-norelax-ld-le.s b/test/ELF/arm-tls-norelax-ld-le.s
new file mode 100644 (file)
index 0000000..9fd822a
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1
+// RUN: ld.lld %t1 --shared -o %t1.so
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi
+// RUN: ld.lld %t1.so %t.o -o %t
+// RUN: llvm-objdump -s %t | FileCheck %s
+// REQUIRES: arm
+
+ .global __tls_get_addr
+ .text
+ .p2align  2
+ .global _start
+ .syntax unified
+ .arm
+ .type   _start, %function
+_start:
+.L0:
+ bl __tls_get_addr
+
+ .word   x(tlsldm) + (. - .L0 - 8)
+ .word   x(tlsldo)
+ .word   y(tlsldo)
+
+ .section        .tbss,"awT",%nobits
+ .p2align  2
+ .type   y, %object
+y:
+ .space  4
+ .section        .tdata,"awT",%progbits
+ .p2align  2
+ .type   x, %object
+x:
+ .word   10
+
+// CHECK: Contents of section .got:
+// CHECK-NEXT:  13064 01000000 00000000
diff --git a/test/ELF/arm-undefined-weak.s b/test/ELF/arm-undefined-weak.s
new file mode 100644 (file)
index 0000000..57a3f57
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t2 | FileCheck %s
+// REQUIRES: arm
+
+// Check that the ARM ABI rules for undefined weak symbols are applied.
+// Branch instructions are resolved to the next instruction. Undefined
+// Symbols in relative are resolved to the place so S - P + A = A.
+
+ .syntax unified
+
+ .weak target
+
+ .text
+ .global _start
+_start:
+// R_ARM_JUMP24
+ b target
+// R_ARM_CALL
+ bl target
+// R_ARM_CALL with exchange
+ blx target
+// R_ARM_MOVT_PREL
+ movt r0, :upper16:target - .
+// R_ARM_MOVW_PREL_NC
+ movw r0, :lower16:target - .
+// R_ARM_REL32
+ .word target - .
+
+// CHECK: Disassembly of section .text:
+// 69636 = 0x11004
+// CHECK:         11000: {{.*}} b       #-4 <_start+0x4>
+// CHECK-NEXT:    11004: {{.*}} bl      #-4 <_start+0x8>
+// blx is transformed into bl so we don't change state
+// CHECK-NEXT:    11008: {{.*}} bl      #-4 <_start+0xC>
+// CHECK-NEXT:    1100c: {{.*}} movt    r0, #0
+// CHECK-NEXT:    11010: {{.*}} movw    r0, #0
+// CHECK:         11014: {{.*}} .word   0x00000000
+
diff --git a/test/ELF/arm-use-r-output.s b/test/ELF/arm-use-r-output.s
new file mode 100644 (file)
index 0000000..9183624
--- /dev/null
@@ -0,0 +1,13 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -r %t.o -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+
+// We used to crash using the output of -r because of the relative order of
+// SHF_LINK_ORDER sections.
+
+// That can be fixed by changing -r or making the regular link more flexible,
+// so this is an end to end test.
+
+       .fnstart
+       .fnend
diff --git a/test/ELF/as-needed-no-reloc.s b/test/ELF/as-needed-no-reloc.s
new file mode 100644 (file)
index 0000000..f8c34f8
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t %t.o --as-needed %t2.so
+# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck %s
+
+
+# There must be a NEEDED entry for each undefined
+
+# CHECK:      Name: bar
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global
+# CHECK-NEXT: Type: Function
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined
+
+# CHECK: NEEDED Shared library: [{{.*}}as-needed-no-reloc{{.*}}2.so]
+
+        .globl _start
+_start:
+        .global bar
diff --git a/test/ELF/as-needed.s b/test/ELF/as-needed.s
new file mode 100644 (file)
index 0000000..37c6103
--- /dev/null
@@ -0,0 +1,45 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared2.s -o %t3.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared3.s -o %t4.o
+// RUN: ld.lld -shared %t2.o -soname shared1 -o %t2.so
+// RUN: ld.lld -shared %t3.o -soname shared2 -o %t3.so
+// RUN: ld.lld -shared %t4.o -soname shared3 -o %t4.so
+
+/// Check if --as-needed actually works.
+
+// RUN: ld.lld %t.o %t2.so %t3.so %t4.so -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+// RUN: ld.lld --as-needed %t.o %t2.so %t3.so %t4.so -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s
+
+// RUN: ld.lld --as-needed %t.o %t2.so --no-as-needed %t3.so %t4.so -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+/// GROUP directive is the same as --as-needed.
+
+// RUN: echo "GROUP(\"%t2.so\" \"%t3.so\" \"%t4.so\")" > %t.script
+// RUN: ld.lld %t.o %t.script -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+// RUN: echo "GROUP(AS_NEEDED(\"%t2.so\" \"%t3.so\" \"%t4.so\"))" > %t.script
+// RUN: ld.lld %t.o %t.script -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s
+
+// CHECK: NEEDED Shared library: [shared1]
+// CHECK: NEEDED Shared library: [shared2]
+// CHECK: NEEDED Shared library: [shared3]
+
+// CHECK2:     NEEDED Shared library: [shared1]
+// CHECK2-NOT: NEEDED Shared library: [shared2]
+// CHECK2-NOT: NEEDED Shared library: [shared3]
+
+.global _start
+_start:
+.data
+.long bar
+.long zed
+.weak baz
+  call baz
diff --git a/test/ELF/auxiliary.s b/test/ELF/auxiliary.s
new file mode 100644 (file)
index 0000000..18fbdf0
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -f aaa --auxiliary bbb -o %t
+# RUN: llvm-readobj --dynamic-table %t | FileCheck %s
+
+# CHECK:      DynamicSection [
+# CHECK-NEXT: Tag                Type          Name/Value
+# CHECK-NEXT: 0x000000007FFFFFFD AUXILIARY     Auxiliary library: [aaa]
+# CHECK-NEXT: 0x000000007FFFFFFD AUXILIARY     Auxiliary library: [bbb]
+
+# RUN: not ld.lld %t.o -f aaa --auxiliary bbb -o %t 2>&1 \
+# RUN:    | FileCheck -check-prefix=ERR %s
+# ERR: -f may not be used without -shared
diff --git a/test/ELF/avoid-empty-program-headers.s b/test/ELF/avoid-empty-program-headers.s
new file mode 100644 (file)
index 0000000..271d1a3
--- /dev/null
@@ -0,0 +1,78 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -program-headers %tout | FileCheck %s
+
+.global _start
+_start:
+        retq
+
+.section .tbss,"awT",@nobits
+        .zero 4
+// FIXME: Test that we don't create unecessary empty PT_LOAD and PT_GNU_RELRO
+// for the .tbss section.
+
+// CHECK:      ProgramHeaders [
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_PHDR (0x6)
+// CHECK-NEXT:     Offset: 0x40
+// CHECK-NEXT:     VirtualAddress: 0x200040
+// CHECK-NEXT:     PhysicalAddress: 0x200040
+// CHECK-NEXT:     FileSize: 280
+// CHECK-NEXT:     MemSize: 280
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 8
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x200000
+// CHECK-NEXT:     PhysicalAddress: 0x200000
+// CHECK-NEXT:     FileSize: 344
+// CHECK-NEXT:     MemSize: 344
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x1000
+// CHECK-NEXT:     VirtualAddress: 0x201000
+// CHECK-NEXT:     PhysicalAddress: 0x201000
+// CHECK-NEXT:     FileSize: 1
+// CHECK-NEXT:     MemSize: 1
+// CHECK-NEXT:     Flags [ (0x5)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_X (0x1)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_TLS (0x7)
+// CHECK-NEXT:     Offset: 0x1001
+// CHECK-NEXT:     VirtualAddress: 0x201001
+// CHECK-NEXT:     PhysicalAddress: 0x201001
+// CHECK-NEXT:     FileSize: 0
+// CHECK-NEXT:     MemSize: 4
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_GNU_STACK (0x6474E551)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x0
+// CHECK-NEXT:     PhysicalAddress: 0x0
+// CHECK-NEXT:     FileSize: 0
+// CHECK-NEXT:     MemSize: 0
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/bad-archive.s b/test/ELF/bad-archive.s
new file mode 100644 (file)
index 0000000..39c8e16
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+
+// Check bad archive error reporting with --whole-archive
+// and without it.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: not ld.lld %t.o %p/Inputs/bad-archive.a -o %t 2>&1 | FileCheck %s
+// RUN: not ld.lld %t.o --whole-archive %p/Inputs/bad-archive.a -o %t 2>&1 | FileCheck %s
+// CHECK: bad-archive.a: failed to parse archive
+
+.globl _start
+_start:
diff --git a/test/ELF/basic-aarch64.s b/test/ELF/basic-aarch64.s
new file mode 100644 (file)
index 0000000..144fe6a
--- /dev/null
@@ -0,0 +1,209 @@
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+# REQUIRES: aarch64
+
+# exits with return code 42 on FreeBSD/AArch64
+.globl _start
+_start:
+  mov    x0, 42
+  mov    x8, 1
+  svc    0
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: FreeBSD (0x9)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_AARCH64 (0xB7)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: [[ENTRY:0x[0-9A-F]+]]
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x10098
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 6
+# CHECK-NEXT:   StringTableSectionIndex: 4
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x20000
+# CHECK-NEXT:     Offset: 0x10000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .comment
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x30)
+# CHECK-NEXT:       SHF_MERGE (0x10)
+# CHECK-NEXT:       SHF_STRINGS (0x20)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1000C
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x10018
+# CHECK-NEXT:     Size: 72
+# CHECK-NEXT:     Link: 5
+# CHECK-NEXT:     Info: 2
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x10060
+# CHECK-NEXT:     Size: 42
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1008A
+# CHECK-NEXT:     Size: 13
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: $x.0
+# CHECK-NEXT:     Value: 0x20000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _start
+# CHECK-NEXT:     Value: [[ENTRY]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x10040
+# CHECK-NEXT:     PhysicalAddress: 0x10040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x10000
+# CHECK-NEXT:     PhysicalAddress: 0x10000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x20000
+# CHECK-NEXT:     PhysicalAddress: 0x20000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/basic-avr.s b/test/ELF/basic-avr.s
new file mode 100644 (file)
index 0000000..c8a3af9
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: avr
+# RUN: llvm-mc -filetype=obj -triple=avr-unknown-linux -mcpu=atmega328p %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe -Ttext=0
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+main:
+  call foo
+foo:
+  jmp foo
+
+# CHECK:      main:
+# CHECK-NEXT:   0: 0e 94 02 00 <unknown>
+# CHECK:      foo:
+# CHECK-NEXT:   4: 0c 94 02 00 <unknown>
diff --git a/test/ELF/basic-freebsd.s b/test/ELF/basic-freebsd.s
new file mode 100644 (file)
index 0000000..375fdb5
--- /dev/null
@@ -0,0 +1,25 @@
+# Verify that OSABI is set to the correct value.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+.globl _start
+_start:
+  mov $1, %rax
+  mov $42, %rdi
+  syscall
+
+# CHECK: ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: FreeBSD (0x9)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_X86_64 (0x3E)
diff --git a/test/ELF/basic-mips.s b/test/ELF/basic-mips.s
new file mode 100644 (file)
index 0000000..4c7a66c
--- /dev/null
@@ -0,0 +1,307 @@
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t.exe \
+# RUN:   | FileCheck %s
+
+# REQUIRES: mips
+
+# Exits with return code 1 on Linux.
+        .globl  __start
+__start:
+        li      $a0,1
+        li      $v0,4001
+        syscall
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 32-bit (0x1)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_MIPS (0x8)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: 0x20000
+# CHECK-NEXT:   ProgramHeaderOffset: 0x34
+# CHECK-NEXT:   SectionHeaderOffset: 0x200A0
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     EF_MIPS_ABI_O32
+# CHECK-NEXT:     EF_MIPS_ARCH_32
+# CHECK-NEXT:     EF_MIPS_CPIC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 52
+# CHECK-NEXT:   ProgramHeaderEntrySize: 32
+# CHECK-NEXT:   ProgramHeaderCount: 5
+# CHECK-NEXT:   SectionHeaderEntrySize: 40
+# CHECK-NEXT:   SectionHeaderCount: 11
+# CHECK-NEXT:   StringTableSectionIndex: 9
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .MIPS.abiflags
+# CHECK-NEXT:     Type: SHT_MIPS_ABIFLAGS (0x7000002A)
+# CHECK-NEXT:     Flags [ (0x2)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x100D8
+# CHECK-NEXT:     Offset: 0xD8
+# CHECK-NEXT:     Size: 24
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .reginfo
+# CHECK-NEXT:     Type: SHT_MIPS_REGINFO (0x70000006)
+# CHECK-NEXT:     Flags [ (0x2)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x100F0
+# CHECK-NEXT:     Offset: 0xF0
+# CHECK-NEXT:     Size: 24
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x20000
+# CHECK-NEXT:     Offset: 0x10000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 16
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .data
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x30000
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 16
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .got
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x10000003)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_MIPS_GPREL (0x10000000)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x30000
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 16
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 6
+# CHECK-NEXT:     Name: .bss
+# CHECK-NEXT:     Type: SHT_NOBITS (0x8)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x30010
+# CHECK-NEXT:     Offset: 0x20008
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 16
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 7
+# CHECK-NEXT:     Name: .comment
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x30)
+# CHECK-NEXT:       SHF_MERGE (0x10)
+# CHECK-NEXT:       SHF_STRINGS (0x20)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x20008
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 8
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x20010
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 10
+# CHECK-NEXT:     Info: 2
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 16
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 9
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x20040
+# CHECK-NEXT:     Size: 82
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 10
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x20092
+# CHECK-NEXT:     Size: 13
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _gp
+# CHECK-NEXT:     Value: 0x37FF0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other [ (0x2)
+# CHECK-NEXT:       STV_HIDDEN (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Section: Absolute
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: __start
+# CHECK-NEXT:     Value: 0x20000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x34
+# CHECK-NEXT:     VirtualAddress: 0x10034
+# CHECK-NEXT:     PhysicalAddress: 0x10034
+# CHECK-NEXT:     FileSize: 160
+# CHECK-NEXT:     MemSize: 160
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x10000
+# CHECK-NEXT:     PhysicalAddress: 0x10000
+# CHECK-NEXT:     FileSize: 264
+# CHECK-NEXT:     MemSize: 264
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x10000
+# CHECK-NEXT:     VirtualAddress: 0x20000
+# CHECK-NEXT:     PhysicalAddress: 0x20000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     VirtualAddress: 0x30000
+# CHECK-NEXT:     PhysicalAddress: 0x30000
+# CHECK-NEXT:     FileSize: 8
+# CHECK-NEXT:     MemSize: 16
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 65536
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:    Type: PT_GNU_STACK
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_W
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:]
diff --git a/test/ELF/basic-ppc.s b/test/ELF/basic-ppc.s
new file mode 100644 (file)
index 0000000..4a36af9
--- /dev/null
@@ -0,0 +1,317 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t
+# RUN: ld.lld -discard-all -shared %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# exits with return code 42 on FreeBSD
+.text
+ li      0,1
+ li      3,1
+ sc
+
+// CHECK: Format: ELF32-ppc
+// CHECK-NEXT: Arch: powerpc
+// CHECK-NEXT: AddressSize: 32bit
+// CHECK-NEXT: LoadName:
+// CHECK-NEXT: ElfHeader {
+// CHECK-NEXT:   Ident {
+// CHECK-NEXT:     Magic: (7F 45 4C 46)
+// CHECK-NEXT:     Class: 32-bit (0x1)
+// CHECK-NEXT:     DataEncoding: BigEndian (0x2)
+// CHECK-NEXT:     FileVersion: 1
+// CHECK-NEXT:     OS/ABI: FreeBSD (0x9)
+// CHECK-NEXT:     ABIVersion: 0
+// CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Type: SharedObject (0x3)
+// CHECK-NEXT:   Machine: EM_PPC (0x14)
+// CHECK-NEXT:   Version: 1
+// CHECK-NEXT:   Entry: 0x1000
+// CHECK-NEXT:   ProgramHeaderOffset: 0x34
+// CHECK-NEXT:   SectionHeaderOffset: 0x20AC
+// CHECK-NEXT:   Flags [ (0x0)
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   HeaderSize: 52
+// CHECK-NEXT:   ProgramHeaderEntrySize: 32
+// CHECK-NEXT:   ProgramHeaderCount: 7
+// CHECK-NEXT:   SectionHeaderEntrySize: 40
+// CHECK-NEXT:   SectionHeaderCount: 10
+// CHECK-NEXT:   StringTableSectionIndex: 8
+// CHECK-NEXT: }
+// CHECK-NEXT: Sections [
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 0
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Type: SHT_NULL (0x0)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 0
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 1
+// CHECK-NEXT:     Name: .dynsym
+// CHECK-NEXT:     Type: SHT_DYNSYM (0xB)
+// CHECK-NEXT:     Flags [ (0x2)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x114
+// CHECK-NEXT:     Offset: 0x114
+// CHECK-NEXT:     Size: 16
+// CHECK-NEXT:     Link: 3
+// CHECK-NEXT:     Info: 1
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 16
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000000 00000000 00000000 00000000  |................|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 2
+// CHECK-NEXT:     Name: .hash
+// CHECK-NEXT:     Type: SHT_HASH (0x5)
+// CHECK-NEXT:     Flags [ (0x2)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x124
+// CHECK-NEXT:     Offset: 0x124
+// CHECK-NEXT:     Size: 16
+// CHECK-NEXT:     Link: 1
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 4
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000001 00000001 00000000 00000000  |................|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 3
+// CHECK-NEXT:     Name: .dynstr
+// CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+// CHECK-NEXT:     Flags [ (0x2)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x134
+// CHECK-NEXT:     Offset: 0x134
+// CHECK-NEXT:     Size: 1
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 1
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00                                   |.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 4
+// CHECK-NEXT:     Name: .text
+// CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:       SHF_EXECINSTR (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x1000
+// CHECK-NEXT:     Offset: 0x1000
+// CHECK-NEXT:     Size: 12
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 38000001 38600001 44000002           |8...8`..D...|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 5
+// CHECK-NEXT:     Name: .dynamic
+// CHECK-NEXT:     Type: SHT_DYNAMIC (0x6)
+// CHECK-NEXT:     Flags [ (0x3)
+// CHECK-NEXT:       SHF_ALLOC (0x2)
+// CHECK-NEXT:       SHF_WRITE (0x1)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x2000
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     Size: 48
+// CHECK-NEXT:     Link: 3
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 8
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000006 00000114 0000000B 00000010  |................|
+// CHECK-NEXT:       0010: 00000005 00000134 0000000A 00000001  |.......4........|
+// CHECK-NEXT:       0020: 00000004 00000124 00000000 00000000  |.......$........|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 6
+// CHECK-NEXT:     Name: .comment
+// CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT:     Flags [ (0x30)
+// CHECK-NEXT:       SHF_MERGE (0x10)
+// CHECK-NEXT:       SHF_STRINGS (0x20)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x2030
+// CHECK-NEXT:     Size: 8
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 1
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 4C4C4420 312E3000 |LLD 1.0.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 7
+// CHECK-NEXT:     Name: .symtab
+// CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x2038
+// CHECK-NEXT:     Size: 32
+// CHECK-NEXT:     Link: 9
+// CHECK-NEXT:     Info: 2
+// CHECK-NEXT:     AddressAlignment: 4
+// CHECK-NEXT:     EntrySize: 16
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 00000000 00000000 00000000 00000000  |................|
+// CHECK-NEXT:       0010: 00000001 00002000 00000000 00020005  |...... .........|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 8
+// CHECK-NEXT:     Name: .shstrtab
+// CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x2058
+// CHECK-NEXT:     Size: 73
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 1
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 002E6479 6E73796D 002E6861 7368002E  |..dynsym..hash..|
+// CHECK-NEXT:       0010: 64796E73 7472002E 74657874 002E6479  |dynstr..text..dy|
+// CHECK-NEXT:       0020: 6E616D69 63002E63 6F6D6D65 6E74002E  |namic..comment..|
+// CHECK-NEXT:       0030: 73796D74 6162002E 73687374 72746162  |symtab..shstrtab|
+// CHECK-NEXT:       0040: 002E7374 72746162 00                 |..strtab.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index: 9
+// CHECK-NEXT:     Name: .strtab
+// CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+// CHECK-NEXT:     Flags [ (0x0)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x20A1
+// CHECK-NEXT:     Size: 1
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 1
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 005F4459 4E414D49 4300               |._DYNAMIC.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK-NEXT: ProgramHeaders [
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_PHDR (0x6)
+// CHECK-NEXT:     Offset: 0x34
+// CHECK-NEXT:     VirtualAddress: 0x34
+// CHECK-NEXT:     PhysicalAddress: 0x34
+// CHECK-NEXT:     FileSize: 224
+// CHECK-NEXT:     MemSize: 224
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x0
+// CHECK-NEXT:     PhysicalAddress: 0x0
+// CHECK-NEXT:     FileSize: 309
+// CHECK-NEXT:     MemSize: 309
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x1000
+// CHECK-NEXT:     VirtualAddress: 0x1000
+// CHECK-NEXT:     PhysicalAddress: 0x1000
+// CHECK-NEXT:     FileSize: 12
+// CHECK-NEXT:     MemSize: 12
+// CHECK-NEXT:     Flags [ (0x5)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_X (0x1)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_LOAD (0x1)
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     VirtualAddress: 0x2000
+// CHECK-NEXT:     PhysicalAddress: 0x2000
+// CHECK-NEXT:     FileSize: 48
+// CHECK-NEXT:     MemSize: 48
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4096
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_DYNAMIC (0x2)
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     VirtualAddress: 0x2000
+// CHECK-NEXT:     PhysicalAddress: 0x2000
+// CHECK-NEXT:     FileSize: 48
+// CHECK-NEXT:     MemSize: 48
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 4
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_GNU_RELRO (0x6474E552)
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     VirtualAddress: 0x2000
+// CHECK-NEXT:     PhysicalAddress: 0x2000
+// CHECK-NEXT:     FileSize: 48
+// CHECK-NEXT:     MemSize: 4096
+// CHECK-NEXT:     Flags [ (0x4)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 1
+// CHECK-NEXT:   }
+// CHECK-NEXT:   ProgramHeader {
+// CHECK-NEXT:     Type: PT_GNU_STACK (0x6474E551)
+// CHECK-NEXT:     Offset: 0x0
+// CHECK-NEXT:     VirtualAddress: 0x0
+// CHECK-NEXT:     PhysicalAddress: 0x0
+// CHECK-NEXT:     FileSize: 0
+// CHECK-NEXT:     MemSize: 0
+// CHECK-NEXT:     Flags [ (0x6)
+// CHECK-NEXT:       PF_R (0x4)
+// CHECK-NEXT:       PF_W (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment: 0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/basic-sparcv9.s b/test/ELF/basic-sparcv9.s
new file mode 100644 (file)
index 0000000..983224c
--- /dev/null
@@ -0,0 +1,200 @@
+# RUN: llvm-mc -filetype=obj -triple=sparc64-unknown-openbsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+# REQUIRES: sparc
+
+# exits with return code 42 on OpenBSD/sparc64
+.global _start
+_start:
+  mov  42, %o0
+  mov  1, %g1
+  ta   0
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: BigEndian (0x2)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_SPARCV9 (0x2B)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: [[ENTRY:0x[0-9A-F]+]]
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x100080
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 6
+# CHECK-NEXT:   StringTableSectionIndex: 4
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x200000
+# CHECK-NEXT:     Offset: 0x100000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .comment
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x30)
+# CHECK-NEXT:       SHF_MERGE (0x10)
+# CHECK-NEXT:       SHF_STRINGS (0x20)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x10000C
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100018
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 5
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100048
+# CHECK-NEXT:     Size: 42
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100072
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _start
+# CHECK-NEXT:     Value: [[ENTRY]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x100040
+# CHECK-NEXT:     PhysicalAddress: 0x100040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x100000
+# CHECK-NEXT:     PhysicalAddress: 0x100000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 1048576
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x100000
+# CHECK-NEXT:     VirtualAddress: 0x200000
+# CHECK-NEXT:     PhysicalAddress: 0x200000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 1048576
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/basic.s b/test/ELF/basic.s
new file mode 100644 (file)
index 0000000..c62a516
--- /dev/null
@@ -0,0 +1,252 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+# RUN: ld.lld %t -o /dev/null
+
+# exits with return code 42 on linux
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_X86_64 (0x3E)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: [[ENTRY:0x[0-9A-F]+]]
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x1080
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 6
+# CHECK-NEXT:   StringTableSectionIndex: 4
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x201000
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     Size: 16
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .comment
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x30)
+# CHECK-NEXT:       SHF_MERGE (0x10)
+# CHECK-NEXT:       SHF_STRINGS (0x20)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1010
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1018
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 5
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1048
+# CHECK-NEXT:     Size: 42
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1072
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _start
+# CHECK-NEXT:     Value: [[ENTRY]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x200040
+# CHECK-NEXT:     PhysicalAddress: 0x200040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x200000
+# CHECK-NEXT:     PhysicalAddress: 0x200000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x201000
+# CHECK-NEXT:     PhysicalAddress: 0x201000
+# CHECK-NEXT:     FileSize: 16
+# CHECK-NEXT:     MemSize: 16
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# Test for the response file (POSIX quoting style)
+# RUN: echo " -o %t2" > %t.responsefile
+# RUN: ld.lld %t --rsp-quoting=posix @%t.responsefile
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \
+# RUN:   | FileCheck %s
+
+# Test for the response file (Windows quoting style)
+# RUN: echo " c:\blah\foo" > %t.responsefile
+# RUN: not ld.lld --rsp-quoting=windows %t @%t.responsefile 2>&1 | FileCheck \
+# RUN:   %s --check-prefix=WINRSP
+# WINRSP: cannot open c:\blah\foo
+
+# Test for the response file (invalid quoting style)
+# RUN: not ld.lld --rsp-quoting=patatino %t 2>&1 | FileCheck %s \
+# RUN:   --check-prefix=INVRSP
+# INVRSP: invalid response file quoting: patatino
+
+# RUN: not ld.lld %t.foo -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=MISSING %s
+# MISSING: cannot open {{.*}}.foo: {{[Nn]}}o such file or directory
+
+# RUN: not ld.lld -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=NO_INPUT %s
+# NO_INPUT: ld.lld{{.*}}: no input files
+
+# RUN: not ld.lld %t.no.such.file -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=CANNOT_OPEN %s
+# CANNOT_OPEN: cannot open {{.*}}.no.such.file: {{[Nn]}}o such file or directory
+
+# RUN: not ld.lld %t -o 2>&1 | FileCheck --check-prefix=NO_O_VAL %s
+# NO_O_VAL: -o: missing argument
+
+# RUN: not ld.lld --foo 2>&1 | FileCheck --check-prefix=UNKNOWN %s
+# UNKNOWN: unknown argument: --foo
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t %t -o %t2 2>&1 | FileCheck --check-prefix=DUP %s
+# DUP:      duplicate symbol: _start
+# DUP-NEXT: >>> defined at {{.*}}:(.text+0x0)
+# DUP-NEXT: >>> defined at {{.*}}:(.text+0x0)
+
+# RUN: not ld.lld %t -o %t -m wrong_emul_fbsd 2>&1 | FileCheck --check-prefix=UNKNOWN_EMUL %s
+# UNKNOWN_EMUL: unknown emulation: wrong_emul_fbsd
+
+# RUN: not ld.lld %t --lto-partitions=0 2>&1 | FileCheck --check-prefix=NOTHREADS %s
+# NOTHREADS: --lto-partitions: number of threads must be > 0
+
+# RUN: not ld.lld %t --thinlto-jobs=0 2>&1 | FileCheck --check-prefix=NOTHREADSTHIN %s
+# NOTHREADSTHIN: --thinlto-jobs: number of threads must be > 0
diff --git a/test/ELF/basic32.s b/test/ELF/basic32.s
new file mode 100644 (file)
index 0000000..cbf67ee
--- /dev/null
@@ -0,0 +1,179 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -program-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+# exits with return code 42 on linux
+.globl _start
+_start:
+  mov $1, %eax
+  mov $42, %ebx
+  int $0x80
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 32-bit (0x1)
+# CHECK-NEXT:     DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_386 (0x3)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: 0x11000
+# CHECK-NEXT:   ProgramHeaderOffset: 0x34
+# CHECK-NEXT:   SectionHeaderOffset: 0x1068
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 52
+# CHECK-NEXT:   ProgramHeaderEntrySize: 32
+# CHECK-NEXT:   ProgramHeaderCount: 4
+# CHECK-NEXT:   SectionHeaderEntrySize: 40
+# CHECK-NEXT:   SectionHeaderCount: 6
+# CHECK-NEXT:   StringTableSectionIndex: 4
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x11000
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .comment
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x30)
+# CHECK-NEXT:       SHF_MERGE (0x10)
+# CHECK-NEXT:       SHF_STRINGS (0x20)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x100C
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1014
+# CHECK-NEXT:     Size: 32
+# CHECK-NEXT:     Link: 5
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 16
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x1034
+# CHECK-NEXT:     Size: 42
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB (0x3)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x105E
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x34
+# CHECK-NEXT:     VirtualAddress: 0x10034
+# CHECK-NEXT:     PhysicalAddress: 0x10034
+# CHECK-NEXT:     FileSize: 128
+# CHECK-NEXT:     MemSize: 128
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x10000
+# CHECK-NEXT:     PhysicalAddress: 0x10000
+# CHECK-NEXT:     FileSize: 180
+# CHECK-NEXT:     MemSize: 180
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x11000
+# CHECK-NEXT:     PhysicalAddress: 0x11000
+# CHECK-NEXT:     FileSize: 12
+# CHECK-NEXT:     MemSize: 12
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/basic64be.s b/test/ELF/basic64be.s
new file mode 100644 (file)
index 0000000..c39669b
--- /dev/null
@@ -0,0 +1,309 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld -discard-all %t -o %t2
+# RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# exits with return code 42 on linux
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+# generate .toc and .toc1 sections to make sure that the ordering is as
+# intended (.toc before .toc1, and both before .opd).
+.section        ".toc1","aw"
+.quad          22, 37, 89, 47
+
+.section        ".toc","aw"
+.quad          45, 86, 72, 24
+
+.text
+.Lfoo:
+       li      0,1
+       li      3,42
+       sc
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:   Ident {
+# CHECK-NEXT:     Magic: (7F 45 4C 46)
+# CHECK-NEXT:     Class: 64-bit (0x2)
+# CHECK-NEXT:     DataEncoding: BigEndian (0x2)
+# CHECK-NEXT:     FileVersion: 1
+# CHECK-NEXT:     OS/ABI: SystemV (0x0)
+# CHECK-NEXT:     ABIVersion: 0
+# CHECK-NEXT:     Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Type: Executable (0x2)
+# CHECK-NEXT:   Machine: EM_PPC64 (0x15)
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Entry: 0x10020040
+# CHECK-NEXT:   ProgramHeaderOffset: 0x40
+# CHECK-NEXT:   SectionHeaderOffset: 0x30080
+# CHECK-NEXT:   Flags [ (0x0)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   HeaderSize: 64
+# CHECK-NEXT:   ProgramHeaderEntrySize: 56
+# CHECK-NEXT:   ProgramHeaderCount: 6
+# CHECK-NEXT:   SectionHeaderEntrySize: 64
+# CHECK-NEXT:   SectionHeaderCount: 10
+# CHECK-NEXT:   StringTableSectionIndex: 8
+# CHECK-NEXT: }
+# CHECK-NEXT: Sections [
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 0
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Type: SHT_NULL (0x0)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 0
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 1
+# CHECK-NEXT:     Name: .text
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_EXECINSTR (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10010000
+# CHECK-NEXT:     Offset: 0x10000
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 4
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK:          )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Name: .toc
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020000
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     Size: 32
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:      0000: 00000000 0000002D 00000000 00000056 |.......-.......V|
+# CHECK-NEXT:      0010: 00000000 00000048 00000000 00000018 |.......H........|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .toc1
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020020
+# CHECK-NEXT:     Offset: 0x20020
+# CHECK-NEXT:     Size: 32
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 00000000 00000016 00000000 00000025  |...............%|
+# CHECK-NEXT:       0010: 00000000 00000059 00000000 0000002F  |.......Y......./|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .opd
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020040
+# CHECK-NEXT:     Offset: 0x20040
+# CHECK-NEXT:     Size: 24
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 00000000 10010000 00000000 10038000 |................|
+# CHECK-NEXT:       0010: 00000000 00000000                   |........|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .got
+# CHECK-NEXT:     Type: SHT_PROGBITS
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       SHF_ALLOC
+# CHECK-NEXT:       SHF_WRITE
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10030000
+# CHECK-NEXT:     Offset: 0x30000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 6
+# CHECK-NEXT:     Name: .comment
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x30)
+# CHECK-NEXT:       SHF_MERGE (0x10)
+# CHECK-NEXT:       SHF_STRINGS (0x20)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x30000
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:         0000: 4C4C4420 312E3000 |LLD 1.0.|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 7
+# CHECK-NEXT:     Name: .symtab
+# CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x30008
+# CHECK-NEXT:     Size: 48
+# CHECK-NEXT:     Link: 9
+# CHECK-NEXT:     Info: 1
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 24
+# CHECK-NEXT:     SectionData (
+# CHECK:          )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 8
+# CHECK-NEXT:     Name: .shstrtab
+# CHECK-NEXT:     Type: SHT_STRTAB
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x30038
+# CHECK-NEXT:     Size: 63
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK:          )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 9
+# CHECK-NEXT:     Name: .strtab
+# CHECK-NEXT:     Type: SHT_STRTAB
+# CHECK-NEXT:     Flags [ (0x0)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset: 0x30077
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 1
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 005F7374 61727400                    |._start.|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x10000040
+# CHECK-NEXT:     PhysicalAddress: 0x10000040
+# CHECK-NEXT:     FileSize: 336
+# CHECK-NEXT:     MemSize: 336
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x10000000
+# CHECK-NEXT:    PhysicalAddress: 0x10000000
+# CHECK-NEXT:    FileSize: 400
+# CHECK-NEXT:    MemSize: 400
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 65536
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x10000
+# CHECK-NEXT:    VirtualAddress: 0x10010000
+# CHECK-NEXT:    PhysicalAddress: 0x10010000
+# CHECK-NEXT:    FileSize: 12
+# CHECK-NEXT:    MemSize: 12
+# CHECK-NEXT:    Flags [ (0x5)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_X (0x1)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 65536
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x20000
+# CHECK-NEXT:    VirtualAddress: 0x10020000
+# CHECK-NEXT:    PhysicalAddress: 0x10020000
+# CHECK-NEXT:    FileSize: 65536
+# CHECK-NEXT:    MemSize: 65536
+# CHECK-NEXT:    Flags [ (0x6)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_W (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 65536
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_GNU_RELRO
+# CHECK-NEXT:    Offset: 0x30000
+# CHECK-NEXT:    VirtualAddress: 0x10030000
+# CHECK-NEXT:    PhysicalAddress: 0x10030000
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [ (0x4)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 1
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_GNU_STACK (0x6474E551)
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [ (0x6)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_W (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT: ]
diff --git a/test/ELF/bss-start-common.s b/test/ELF/bss-start-common.s
new file mode 100644 (file)
index 0000000..cedf6a8
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -t -section-headers %t2 | FileCheck %s
+
+# CHECK: Sections:
+# CHECK: Idx Name          Size      Address          Type
+# CHECK:   2 .bss          00000004 0000000000201000 BSS
+# CHECK: SYMBOL TABLE:
+# CHECK: 0000000000201000  .bss 00000000 __bss_start
+
+.global __bss_start
+.text
+_start:
+.comm sym1,4,4
diff --git a/test/ELF/bss.s b/test/ELF/bss.s
new file mode 100644 (file)
index 0000000..abd7f2e
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -sections %t2 | FileCheck %s
+// REQUIRES: x86
+
+// Test that bss takes no space on disk.
+
+// CHECK:        Name: .bss
+// CHECK-NEXT:   Type: SHT_NOBITS
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:     SHF_WRITE
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address:
+// CHECK-NEXT:   Offset: 0x[[OFFSET:.*]]
+// CHECK-NEXT:   Size: 4
+// CHECK-NEXT:   Link: 0
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment:
+// CHECK-NEXT:   EntrySize: 0
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT:   Index:
+// CHECK-NEXT:   Name:
+// CHECK-NEXT:   Type:
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_MERGE
+// CHECK-NEXT:     SHF_STRINGS
+// CHECK-NEXT:   ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset: 0x[[OFFSET]]
+
+        .global _start
+_start:
+
+        .bss
+        .zero 4
diff --git a/test/ELF/bsymbolic-undef.s b/test/ELF/bsymbolic-undef.s
new file mode 100644 (file)
index 0000000..19bb316
--- /dev/null
@@ -0,0 +1,26 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -Bsymbolic %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: undef@
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+call undef@PLT
diff --git a/test/ELF/bsymbolic.s b/test/ELF/bsymbolic.s
new file mode 100644 (file)
index 0000000..5a089d5
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t0.so
+// RUN: ld.lld -shared -Bsymbolic %t.o -o %t1.so
+// RUN: ld.lld -shared -Bsymbolic-functions %t.o -o %t2.so
+// RUN: llvm-readobj -s %t0.so | FileCheck -check-prefix=NOOPTION %s
+// RUN: llvm-readobj -s %t1.so | FileCheck -check-prefix=SYMBOLIC %s
+// RUN: llvm-readobj -s %t2.so | FileCheck -check-prefix=SYMBOLIC %s
+
+// NOOPTION:     Section {
+// NOOPTION:       Name: .plt
+
+// SYMBOLIC: Section {
+// SYMBOLIC-NOT: Name: .plt
+
+.text
+.globl foo
+.type foo,@function
+foo:
+nop
+
+.globl bar
+.type bar,@function
+bar:
+nop
+
+.globl do
+.type do,@function
+do:
+callq foo@PLT
+callq bar@PLT
+
+.weak zed
+.protected zed
+.quad zed
diff --git a/test/ELF/build-id.s b/test/ELF/build-id.s
new file mode 100644 (file)
index 0000000..2d19347
--- /dev/null
@@ -0,0 +1,68 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld --build-id %t -o %t2 -threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s
+# RUN: ld.lld --build-id %t -o %t2 -no-threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s
+
+# RUN: ld.lld --build-id=md5 %t -o %t2 -threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=MD5 %s
+# RUN: ld.lld --build-id=md5 %t -o %t2 -no-threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=MD5 %s
+
+# RUN: ld.lld --build-id=sha1 %t -o %t2 -threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SHA1 %s
+# RUN: ld.lld --build-id=sha1 %t -o %t2 -no-threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SHA1 %s
+
+# RUN: ld.lld --build-id=tree %t -o %t2 -threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SHA1 %s
+# RUN: ld.lld --build-id=tree %t -o %t2 -no-threads
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SHA1 %s
+
+# RUN: ld.lld --build-id=uuid %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=UUID %s
+
+# RUN: ld.lld --build-id=0x12345678 %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=HEX %s
+
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s
+
+# RUN: ld.lld --build-id=md5 --build-id=none %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s
+# RUN: ld.lld --build-id --build-id=none %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s
+# RUN: ld.lld --build-id=none --build-id %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s
+
+.globl _start
+_start:
+  nop
+
+.section .note.test, "a", @note
+   .quad 42
+
+# DEFAULT:      Contents of section .note.test:
+# DEFAULT:      Contents of section .note.gnu.build-id:
+# DEFAULT-NEXT: 04000000 08000000 03000000 474e5500  ............GNU.
+# DEFAULT-NEXT: fd36edb1 f6ff02af
+
+# MD5:      Contents of section .note.gnu.build-id:
+# MD5-NEXT: 04000000 10000000 03000000 474e5500  ............GNU.
+# MD5-NEXT: fc
+
+# SHA1:      Contents of section .note.gnu.build-id:
+# SHA1-NEXT: 04000000 14000000 03000000 474e5500  ............GNU.
+# SHA1-NEXT: 55b1eedb 03b588e1 09987d1d e9a79be7
+
+# UUID:      Contents of section .note.gnu.build-id:
+# UUID-NEXT: 04000000 10000000 03000000 474e5500  ............GNU.
+
+# HEX:      Contents of section .note.gnu.build-id:
+# HEX-NEXT: 04000000 04000000 03000000 474e5500  ............GNU.
+# HEX-NEXT: 12345678
+
+# NONE-NOT: Contents of section .note.gnu.build-id:
diff --git a/test/ELF/color-diagnostics.test b/test/ELF/color-diagnostics.test
new file mode 100644 (file)
index 0000000..074bba2
--- /dev/null
@@ -0,0 +1,18 @@
+# Windows command prompt doesn't support ANSI escape sequences.
+# REQUIRES: shell
+
+# RUN: not ld.lld -xyz -color-diagnostics /nosuchfile 2>&1 \
+# RUN:   | FileCheck -check-prefix=COLOR %s
+# RUN: not ld.lld -xyz -color-diagnostics=always /nosuchfile 2>&1 \
+# RUN:   | FileCheck -check-prefix=COLOR %s
+
+# COLOR: {{ld.lld: .\[0;1;31merror: .\[0munknown argument: -xyz}}
+# COLOR: {{ld.lld: .\[0;1;31merror: .\[0mcannot open /nosuchfile}}
+
+# RUN: not ld.lld /nosuchfile 2>&1 | FileCheck -check-prefix=NOCOLOR %s
+# RUN: not ld.lld -color-diagnostics=never /nosuchfile 2>&1 \
+# RUN:   | FileCheck -check-prefix=NOCOLOR %s
+# RUN: not ld.lld -color-diagnostics=always -no-color-diagnostics \
+# RUN:   /nosuchfile 2>&1 | FileCheck -check-prefix=NOCOLOR %s
+
+# NOCOLOR: ld.lld: error: cannot open /nosuchfile
diff --git a/test/ELF/combrelocs.s b/test/ELF/combrelocs.s
new file mode 100644 (file)
index 0000000..3c8be80
--- /dev/null
@@ -0,0 +1,92 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.out
+# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x1000
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: aaa (1)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x1018
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: aaa (1)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x1010
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: bbb (2)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x1008
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: ccc (3)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x1020
+# CHECK-NEXT:       Type: R_X86_64_64
+# CHECK-NEXT:       Symbol: ddd (4)
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK:      DynamicSection [
+# CHECK-NEXT:   Tag
+# CHECK-NOT:    RELACOUNT
+
+# RUN: ld.lld -z nocombreloc -shared %t.o -o %t.out
+# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | \
+# RUN:    FileCheck --check-prefix=NOCOMB %s
+
+# NOCOMB:      Relocations [
+# NOCOMB-NEXT:    Section ({{.*}}) .rela.dyn {
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x1000
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: aaa (1)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x1008
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: ccc (3)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x1010
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: bbb (2)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x1018
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: aaa (1)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:     Relocation {
+# NOCOMB-NEXT:       Offset: 0x1020
+# NOCOMB-NEXT:       Type: R_X86_64_64
+# NOCOMB-NEXT:       Symbol: ddd (4)
+# NOCOMB-NEXT:       Addend: 0x0
+# NOCOMB-NEXT:     }
+# NOCOMB-NEXT:   }
+# NOCOMB-NEXT:  ]
+# NOCOMB:      DynamicSection [
+# NOCOMB-NEXT:   Tag
+# NOCOMB-NOT:    RELACOUNT
+
+.data
+ .quad aaa
+ .quad ccc
+ .quad bbb
+ .quad aaa
+ .quad ddd
diff --git a/test/ELF/comdat-linkonce.s b/test/ELF/comdat-linkonce.s
new file mode 100644 (file)
index 0000000..78611b4
--- /dev/null
@@ -0,0 +1,9 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o
+// RUN: ld.lld -shared %t.o %t2.o -o %t
+// RUN: ld.lld -shared %t2.o %t.o -o %t
+
+.section .gnu.linkonce.t.zed
+.globl abc
+abc:
+nop
diff --git a/test/ELF/comdat.s b/test/ELF/comdat.s
new file mode 100644 (file)
index 0000000..5b190b1
--- /dev/null
@@ -0,0 +1,92 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o
+// RUN: ld.lld -shared %t.o %t.o %t2.o -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// RUN: llvm-readobj -s -t %t | FileCheck --check-prefix=READ %s
+// REQUIRES: x86
+
+// Check that we don't crash with --gc-section and that we print a list of
+// reclaimed sections on stderr.
+// RUN: ld.lld --gc-sections --print-gc-sections -shared %t.o %t.o %t2.o -o %t \
+// RUN:   2>&1 | FileCheck --check-prefix=GC %s
+// GC: removing unused section from '.text' in file
+// GC: removing unused section from '.text3' in file
+// GC: removing unused section from '.text' in file
+// GC: removing unused section from '.text' in file
+
+        .section       .text2,"axG",@progbits,foo,comdat,unique,0
+foo:
+        nop
+
+// CHECK: Disassembly of section .text2:
+// CHECK-NEXT: foo:
+// CHECK-NEXT:   1000: {{.*}}  nop
+// CHECK-NOT: nop
+
+        .section bar, "ax"
+        call foo
+
+// CHECK: Disassembly of section bar:
+// CHECK-NEXT: bar:
+// 0x1000 - 0x1001 - 5 = -6
+// 0      - 0x1006 - 5 = -4107
+// CHECK-NEXT:   1001: {{.*}}  callq  -6
+// CHECK-NEXT:   1006: {{.*}}  callq  -4107
+
+        .section .text3,"axG",@progbits,zed,comdat,unique,0
+
+
+// READ:      Name: .text2
+// READ-NEXT: Type: SHT_PROGBITS
+// READ-NEXT: Flags [
+// READ-NEXT:   SHF_ALLOC
+// READ-NEXT:   SHF_EXECINSTR
+// READ-NEXT: ]
+
+// READ:      Name: .text3
+// READ-NEXT: Type: SHT_PROGBITS
+// READ-NEXT: Flags [
+// READ-NEXT:   SHF_ALLOC
+// READ-NEXT:   SHF_EXECINSTR
+// READ-NEXT: ]
+
+// READ:      Symbols [
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name:  (0)
+// READ-NEXT:     Value: 0x0
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: Undefined
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: foo
+// READ-NEXT:     Value
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: .text
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: _DYNAMIC
+// READ-NEXT:     Value: 0x2000
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Local
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other [ (0x2)
+// READ-NEXT:       STV_HIDDEN
+// READ-NEXT:     ]
+// READ-NEXT:     Section: .dynamic
+// READ-NEXT:   }
+// READ-NEXT:   Symbol {
+// READ-NEXT:     Name: abc
+// READ-NEXT:     Value: 0x0
+// READ-NEXT:     Size: 0
+// READ-NEXT:     Binding: Global
+// READ-NEXT:     Type: None
+// READ-NEXT:     Other: 0
+// READ-NEXT:     Section: Undefined
+// READ-NEXT:   }
+// READ-NEXT: ]
diff --git a/test/ELF/comment-gc.s b/test/ELF/comment-gc.s
new file mode 100644 (file)
index 0000000..8018ff8
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/comment-gc.s -o %t2.o
+# RUN: ld.lld %t.o %t2.o -o %t1 --gc-sections -shared
+# RUN: llvm-objdump -s %t1 | FileCheck %s
+
+# CHECK:      Contents of section .comment:
+# CHECK-NEXT:  0000 00666f6f 00626172 004c4c44 20312e30 .foo.bar.LLD 1.0
+# CHECK-NEXT:  0010 00 .
+
+.ident "foo"
+
+.globl _start
+_start:
+  nop
diff --git a/test/ELF/common.s b/test/ELF/common.s
new file mode 100644 (file)
index 0000000..c8011a0
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2
+// RUN: ld.lld %t %t2 -o %t3
+// RUN: llvm-readobj -t -s %t3 | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x201000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 22
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK:      Name: sym1
+// CHECK-NEXT: Value: 0x201004
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: sym2
+// CHECK-NEXT: Value: 0x20100C
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: sym3
+// CHECK-NEXT: Value: 0x201014
+// CHECK-NEXT: Size: 2
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: sym4
+// CHECK-NEXT: Value: 0x201000
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+
+.globl _start
+_start:
+
+.comm sym1,4,4
+.comm sym2,8,4
+.comm sym3,2,2
+.comm sym4,4,2
diff --git a/test/ELF/compatible-section-types.s b/test/ELF/compatible-section-types.s
new file mode 100644 (file)
index 0000000..a5dadb8
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t
+// RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+// CHECK: .foo {{0*}}28
+
+.section .foo, "aw", @progbits, unique, 1
+.quad 0
+
+.section .foo, "aw", @init_array, unique, 2
+.quad 0
+
+.section .foo, "aw", @preinit_array, unique, 3
+.quad 0
+
+.section .foo, "aw", @fini_array, unique, 4
+.quad 0
+
+.section .foo, "aw", @note, unique, 5
+.quad 0
diff --git a/test/ELF/compress-debug-sections.s b/test/ELF/compress-debug-sections.s
new file mode 100644 (file)
index 0000000..5fb7ee5
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86, zlib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1 --compress-debug-sections=zlib
+
+# RUN: llvm-objdump -s %t1 | FileCheck %s --check-prefix=ZLIBCONTENT
+# ZLIBCONTENT:     Contents of section .debug_str:
+# ZLIBCONTENT-NOT: AAAAAAAAA
+
+# RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=ZLIBFLAGS
+# ZLIBFLAGS:       Section {
+# ZLIBFLAGS:         Index:
+# ZLIBFLAGS:         Name: .debug_str
+# ZLIBFLAGS-NEXT:    Type: SHT_PROGBITS
+# ZLIBFLAGS-NEXT:    Flags [
+# ZLIBFLAGS-NEXT:      SHF_COMPRESSED
+
+# RUN: llvm-dwarfdump %t1 -debug-dump=str | \
+# RUN:   FileCheck %s --check-prefix=DEBUGSTR
+# DEBUGSTR:     .debug_str contents:
+# DEBUGSTR-NEXT:  AAAAAAAAAAAAAAAAAAAAAAAAAAA
+# DEBUGSTR-NEXT:  BBBBBBBBBBBBBBBBBBBBBBBBBBB
+
+# RUN: not ld.lld %t.o -o %t1 --compress-debug-sections=zlib-gabi 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR %s
+# ERR: unknown --compress-debug-sections value: zlib-gabi
+
+.section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+  .asciz "AAAAAAAAAAAAAAAAAAAAAAAAAAA"
+.Linfo_string1:
+  .asciz "BBBBBBBBBBBBBBBBBBBBBBBBBBB"
diff --git a/test/ELF/compressed-debug-input.s b/test/ELF/compressed-debug-input.s
new file mode 100644 (file)
index 0000000..d96ebdc
--- /dev/null
@@ -0,0 +1,82 @@
+# REQUIRES: zlib, x86
+
+# RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=ZLIB %s
+# ZLIB:      Section {
+# ZLIB:        Index: 2
+# ZLIB:        Name: .debug_str
+# ZLIB-NEXT:   Type: SHT_PROGBITS
+# ZLIB-NEXT:   Flags [
+# ZLIB-NEXT:     SHF_COMPRESSED (0x800)
+# ZLIB-NEXT:     SHF_MERGE (0x10)
+# ZLIB-NEXT:     SHF_STRINGS (0x20)
+# ZLIB-NEXT:   ]
+# ZLIB-NEXT:   Address:
+# ZLIB-NEXT:   Offset:
+# ZLIB-NEXT:   Size:
+# ZLIB-NEXT:   Link:
+# ZLIB-NEXT:   Info:
+# ZLIB-NEXT:   AddressAlignment: 1
+# ZLIB-NEXT:   EntrySize: 1
+# ZLIB-NEXT: }
+
+# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t2
+# RUN: llvm-readobj -sections %t2 | FileCheck -check-prefix=GNU %s
+# GNU:      Section {
+# GNU:        Index: 2
+# GNU:        Name: .zdebug_str
+# GNU-NEXT:   Type: SHT_PROGBITS
+# GNU-NEXT:   Flags [
+# GNU-NEXT:     SHF_MERGE (0x10)
+# GNU-NEXT:     SHF_STRINGS (0x20)
+# GNU-NEXT:   ]
+# GNU-NEXT:   Address:
+# GNU-NEXT:   Offset:
+# GNU-NEXT:   Size:
+# GNU-NEXT:   Link:
+# GNU-NEXT:   Info:
+# GNU-NEXT:   AddressAlignment: 1
+# GNU-NEXT:   EntrySize: 1
+# GNU-NEXT: }
+
+# RUN: ld.lld %t -o %t.so -shared
+# RUN: llvm-readobj -sections -section-data %t.so | FileCheck -check-prefix=DATA %s
+
+# RUN: ld.lld %t2 -o %t2.so -shared
+# RUN: llvm-readobj -sections -section-data %t2.so | FileCheck -check-prefix=DATA %s
+
+# DATA:      Section {
+# DATA:        Index: 6
+# DATA:        Name: .debug_str
+# DATA-NEXT:   Type: SHT_PROGBITS
+# DATA-NEXT:   Flags [
+# DATA-NEXT:     SHF_MERGE (0x10)
+# DATA-NEXT:     SHF_STRINGS (0x20)
+# DATA-NEXT:   ]
+# DATA-NEXT:   Address: 0x0
+# DATA-NEXT:   Offset: 0x1060
+# DATA-NEXT:   Size: 69
+# DATA-NEXT:   Link: 0
+# DATA-NEXT:   Info: 0
+# DATA-NEXT:   AddressAlignment: 1
+# DATA-NEXT:   EntrySize: 0
+# DATA-NEXT:   SectionData (
+# DATA-NEXT:     0000: 73686F72 7420756E 7369676E 65642069  |short unsigned i|
+# DATA-NEXT:     0010: 6E740075 6E736967 6E656420 696E7400  |nt.unsigned int.|
+# DATA-NEXT:     0020: 6C6F6E67 20756E73 69676E65 6420696E  |long unsigned in|
+# DATA-NEXT:     0030: 74006368 61720075 6E736967 6E656420  |t.char.unsigned |
+# DATA-NEXT:     0040: 63686172 00                          |char.|
+# DATA-NEXT:   )
+# DATA-NEXT: }
+
+.section .debug_str,"MS",@progbits,1
+.LASF2:
+ .string "short unsigned int"
+.LASF3:
+ .string "unsigned int"
+.LASF0:
+ .string "long unsigned int"
+.LASF8:
+ .string "char"
+.LASF1:
+ .string "unsigned char"
diff --git a/test/ELF/conflict.s b/test/ELF/conflict.s
new file mode 100644 (file)
index 0000000..4318759
--- /dev/null
@@ -0,0 +1,50 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: not ld.lld %t1.o %t1.o -o %t2 2>&1 | FileCheck -check-prefix=DEMANGLE %s
+
+# DEMANGLE:       duplicate symbol: mul(double, double)
+# DEMANGLE-NEXT:  >>> defined at {{.*}}:(.text+0x0)
+# DEMANGLE-NEXT:  >>> defined at {{.*}}:(.text+0x0)
+# DEMANGLE:       duplicate symbol: foo
+# DEMANGLE-NEXT:  >>> defined at {{.*}}:(.text+0x0)
+# DEMANGLE-NEXT:  >>> defined at {{.*}}:(.text+0x0)
+
+# RUN: not ld.lld %t1.o %t1.o -o %t2 --no-demangle 2>&1 | \
+# RUN:   FileCheck -check-prefix=NO_DEMANGLE %s
+
+# NO_DEMANGLE:      duplicate symbol: _Z3muldd
+# NO_DEMANGLE-NEXT: >>> defined at {{.*}}:(.text+0x0)
+# NO_DEMANGLE-NEXT: >>> defined at {{.*}}:(.text+0x0)
+# NO_DEMANGLE:      duplicate symbol: foo
+# NO_DEMANGLE-NEXT: >>> defined at {{.*}}:(.text+0x0)
+# NO_DEMANGLE-NEXT: >>> defined at {{.*}}:(.text+0x0)
+
+# RUN: not ld.lld %t1.o %t1.o -o %t2 --demangle --no-demangle 2>&1 | \
+# RUN:   FileCheck -check-prefix=NO_DEMANGLE %s
+# RUN: not ld.lld %t1.o %t1.o -o %t2 --no-demangle --demangle 2>&1 | \
+# RUN:   FileCheck -check-prefix=DEMANGLE %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/conflict.s -o %t2.o
+# RUN: llvm-ar rcs %t3.a %t2.o
+# RUN: not ld.lld %t1.o %t3.a -u baz -o %t2 2>&1 | FileCheck -check-prefix=ARCHIVE %s
+
+# ARCHIVE:      duplicate symbol: foo
+# ARCHIVE-NEXT: >>> defined at {{.*}}:(.text+0x0)
+# ARCHIVE-NEXT: >>> defined at {{.*}}:(.text+0x0) in archive {{.*}}.a
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/conflict-debug.s -o %t-dbg.o
+# RUN: not ld.lld %t-dbg.o %t-dbg.o -o %t-dbg 2>&1 | FileCheck -check-prefix=DBGINFO %s
+
+# DBGINFO:      duplicate symbol: zed
+# DBGINFO-NEXT: >>> defined at conflict-debug.s:4
+# DBGINFO-NEXT: >>>            {{.*}}:(.text+0x0)
+# DBGINFO-NEXT: >>> defined at conflict-debug.s:4
+# DBGINFO-NEXT: >>>            {{.*}}:(.text+0x0)
+
+.globl _Z3muldd, foo
+_Z3muldd:
+foo:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/copy-errors.s b/test/ELF/copy-errors.s
new file mode 100644 (file)
index 0000000..d0d6abd
--- /dev/null
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/protected-shared.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+// CHECK: cannot preempt symbol: bar
+// CHECK: >>> defined in {{.*}}.so
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x1)
+// CHECK: symbol 'zed' defined in {{.*}}.so has no type
+
+.global _start
+_start:
+call bar
+call zed
diff --git a/test/ELF/copy-in-shared.s b/test/ELF/copy-in-shared.s
new file mode 100644 (file)
index 0000000..7043985
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-in-shared.s -o %t1.o
+// RUN: ld.lld -shared %t1.o -o %t1.so
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: not ld.lld %t2.o %t1.so -o %t2.so -shared 2>&1 | FileCheck %s
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment
+// CHECK: >>> defined in {{.*}}.so
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+.quad foo
diff --git a/test/ELF/copy-rel-corrupted.s b/test/ELF/copy-rel-corrupted.s
new file mode 100644 (file)
index 0000000..3cdad7c
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/copy-rel-corrupted.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: not ld.lld %t.o %t2.so -o %t.exe 2>&1 | FileCheck %s
+
+// CHECK: error: cannot create a copy relocation for symbol x
+
+.global _start
+_start:
+        call x
diff --git a/test/ELF/copy-rel-pie-error.s b/test/ELF/copy-rel-pie-error.s
new file mode 100644 (file)
index 0000000..6f7677e
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: not ld.lld %t.o %t2.so -o %t.exe -pie 2>&1 | FileCheck %s
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: bar
+// CHECK: >>> defined in {{.*}}.so
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo
+// CHECK: >>> defined in {{.*}}.so
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x8)
+
+.global _start
+_start:
+        .quad bar
+        .quad foo
diff --git a/test/ELF/copy-rel-pie.s b/test/ELF/copy-rel-pie.s
new file mode 100644 (file)
index 0000000..769a243
--- /dev/null
@@ -0,0 +1,44 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe -pie
+// RUN: llvm-readobj -s -r %t.exe | FileCheck %s
+// RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASM %s
+
+.global _start
+_start:
+        call bar
+        call foo
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1010
+
+// CHECK:      Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x4000
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     0x4000 R_X86_64_COPY foo 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section (5) .rela.plt {
+// CHECK-NEXT:     0x2018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// (0x1010 + 0x10) - 0x1005 = 27
+// 0x4000          - 0x100a = 12278
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT:     1000:       e8 1b 00 00 00  callq   27
+// DISASM-NEXT:     1005:       e8 f6 2f 00 00  callq   12278 <foo>
diff --git a/test/ELF/ctors_dtors_priority.s b/test/ELF/ctors_dtors_priority.s
new file mode 100644 (file)
index 0000000..fcddcbb
--- /dev/null
@@ -0,0 +1,48 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority1.s -o %t-crtbegin.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority2.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/ctors_dtors_priority3.s -o %t-crtend.o
+// RUN: ld.lld %t1 %t2 %t-crtend.o %t-crtbegin.o -o %t.exe
+// RUN: llvm-objdump -s %t.exe | FileCheck %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  nop
+
+.section .ctors, "aw", @progbits
+  .quad 1
+.section .ctors.100, "aw", @progbits
+  .quad 2
+.section .ctors.005, "aw", @progbits
+  .quad 3
+.section .ctors, "aw", @progbits
+  .quad 4
+.section .ctors, "aw", @progbits
+  .quad 5
+
+.section .dtors, "aw", @progbits
+  .quad 0x11
+.section .dtors.100, "aw", @progbits
+  .quad 0x12
+.section .dtors.005, "aw", @progbits
+  .quad 0x13
+.section .dtors, "aw", @progbits
+  .quad 0x14
+.section .dtors, "aw", @progbits
+  .quad 0x15
+
+// CHECK:      Contents of section .ctors:
+// CHECK-NEXT: 202000 a1000000 00000000 01000000 00000000
+// CHECK-NEXT: 202010 04000000 00000000 05000000 00000000
+// CHECK-NEXT: 202020 b1000000 00000000 03000000 00000000
+// CHECK-NEXT: 202030 02000000 00000000 c1000000 00000000
+
+// CHECK:      Contents of section .dtors:
+// CHECK-NEXT: 202040 a2000000 00000000 11000000 00000000
+// CHECK-NEXT: 202050 14000000 00000000 15000000 00000000
+// CHECK-NEXT: 202060 b2000000 00000000 13000000 00000000
+// CHECK-NEXT: 202070 12000000 00000000 c2000000 00000000
diff --git a/test/ELF/debug-gc.s b/test/ELF/debug-gc.s
new file mode 100644 (file)
index 0000000..8bcfde1
--- /dev/null
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1 --gc-sections
+# RUN: llvm-objdump -s %t1 | FileCheck %s
+
+# CHECK:      Contents of section .debug_str:
+# CHECK-NEXT:  0000 41414100 42424200 43434300           AAA.BBB.CCC.
+# CHECK:      Contents of section .foo:
+# CHECK-NEXT:  0000 2a000000
+# CHECK:      Contents of section .debug_info:
+# CHECK-NEXT:  0000 00000000 04000000
+
+.globl _start
+_start:
+
+.section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+  .asciz "AAA"
+.Linfo_string1:
+  .asciz "BBB"
+.Linfo_string2:
+  .asciz "CCC"
+
+.section .foo,"M",@progbits,4
+.p2align 2
+  .long 42
+
+.section  .debug_info,"",@progbits
+  .long .Linfo_string0
+  .long .Linfo_string1
diff --git a/test/ELF/debug-gnu-pubnames.s b/test/ELF/debug-gnu-pubnames.s
new file mode 100644 (file)
index 0000000..aebfdfd
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: ld.lld %t.o -o %t1.exe
+# RUN: llvm-readobj -sections %t1.exe | FileCheck %s
+# CHECK: .debug_gnu_pubnames
+# CHECK: .debug_gnu_pubtypes
+
+# RUN: ld.lld -gdb-index %t.o -o %t2.exe
+# RUN: llvm-readobj -sections %t2.exe | FileCheck %s --check-prefix=GDB
+# GDB-NOT: .debug_gnu_pubnames
+# GDB-NOT: .debug_gnu_pubtypes
+
+.section .debug_gnu_pubnames,"",@progbits
+.long 0
+
+.section .debug_gnu_pubtypes,"",@progbits
+.long 0
diff --git a/test/ELF/default-fill.s b/test/ELF/default-fill.s
new file mode 100644 (file)
index 0000000..4ea9495
--- /dev/null
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+# Verify that the fill between sections has a default of interrupt instructions
+# (0xcc on x86/x86_64) for executable sections and zero for other sections.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld %t1.o -o %t1.elf
+# RUN: llvm-objdump -s %t1.elf > %t1.sections
+# RUN: FileCheck %s --input-file %t1.sections --check-prefix=TEXT
+# RUN: FileCheck %s --input-file %t1.sections --check-prefix=DATA
+
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.elf
+# RUN: llvm-objdump -s %t2.elf > %t2.sections
+# RUN: FileCheck %s --input-file %t2.sections --check-prefix=TEXT
+# RUN: FileCheck %s --input-file %t2.sections --check-prefix=DATA
+
+# TEXT: Contents of section .text:
+# TEXT-NEXT: 11cccccc cccccccc cccccccc cccccccc
+# TEXT-NEXT: 22
+# DATA: Contents of section .data:
+# DATA-NEXT: 33000000 00000000 00000000 00000000
+# DATA-NEXT: 44
+
+.section .text.1,"ax",@progbits
+.align 16
+.byte 0x11
+
+.section .text.2,"ax",@progbits
+.align 16
+.byte 0x22
+
+.section .data.1,"a",@progbits
+.align 16
+.byte 0x33
+
+.section .data.2,"a",@progbits
+.align 16
+.byte 0x44
diff --git a/test/ELF/default-output.s b/test/ELF/default-output.s
new file mode 100644 (file)
index 0000000..c0766ac
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# Verify that default output filename is a.out.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: mkdir -p %t.dir
+# RUN: cd %t.dir
+# RUN: rm -f a.out
+# RUN: not llvm-readobj a.out > /dev/null 2>&1
+# RUN: ld.lld %t
+# RUN: llvm-readobj a.out > /dev/null 2>&1
+
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/defined-tls_get_addr.s b/test/ELF/defined-tls_get_addr.s
new file mode 100644 (file)
index 0000000..509c293
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj
+// RUN: ld.lld %t.o -o %t
+
+// Don't error if __tls_get_addr is defined.
+
+.global _start
+.global __tls_get_addr
+_start:
+__tls_get_addr:
+nop
diff --git a/test/ELF/defsym.s b/test/ELF/defsym.s
new file mode 100644 (file)
index 0000000..b821484
--- /dev/null
@@ -0,0 +1,47 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t %t.o --defsym=foo2=foo1
+# RUN: llvm-readobj -t -s %t | FileCheck %s
+# RUN: llvm-objdump -d -print-imm-hex %t | FileCheck %s --check-prefix=USE
+
+## Check that we accept --defsym foo2=foo1 form.
+# RUN: ld.lld -o %t2 %t.o --defsym foo2=foo1
+# RUN: llvm-readobj -t -s %t2 | FileCheck %s
+# RUN: llvm-objdump -d -print-imm-hex %t2 | FileCheck %s --check-prefix=USE
+
+# CHECK:      Symbol {
+# CHECK:        Name: foo1
+# CHECK-NEXT:   Value: 0x123
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type:
+# CHECK-NEXT:   Other:
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: foo1
+# CHECK-NEXT:   Value: 0x123
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type:
+# CHECK-NEXT:   Other:
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+
+## Check we can use foo2 and it that it is an alias for foo1.
+# USE:       Disassembly of section .text:
+# USE-NEXT:  _start:
+# USE-NEXT:    movl $0x123, %edx
+
+# RUN: not ld.lld -o %t %t.o --defsym=foo2=1 2>&1 | FileCheck %s -check-prefix=ERR1
+# ERR1: error: --defsym: symbol name expected, but got 1
+
+# RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR2
+# ERR2: error: -defsym: undefined symbol: und
+
+.globl foo1
+ foo1 = 0x123
+
+.global _start
+_start:
+  movl $foo2, %edx
diff --git a/test/ELF/discard-locals.s b/test/ELF/discard-locals.s
new file mode 100644 (file)
index 0000000..9deaccf
--- /dev/null
@@ -0,0 +1,50 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t
+// RUN: ld.lld -discard-locals %t -o %t2
+// RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+
+.text
+.Lmyvar:
+.Lmyothervar:
+
+// CHECK:   Section {
+// CHECK:     Name: .strtab
+// CHECK-NEXT:     Type: SHT_STRTAB
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 005F7374 61727400                    |._start.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECk-NEXT: ]
diff --git a/test/ELF/discard-merge-locals.s b/test/ELF/discard-merge-locals.s
new file mode 100644 (file)
index 0000000..01b4d33
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2 -shared
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+       leaq    .L.str(%rip), %rdi
+
+       .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+       .asciz  "foobar"
+
+// Test that the .L symbol is omitted
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x2000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/discard-merge-unnamed.s b/test/ELF/discard-merge-unnamed.s
new file mode 100644 (file)
index 0000000..be174f2
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: ld.lld %p/Inputs/discard-merge-unnamed.o -o %t2 -shared
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+
+// Test that the unnamed symbol is SHF_MERGE is omitted.
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x2000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/discard-none.s b/test/ELF/discard-none.s
new file mode 100644 (file)
index 0000000..89e06fd
--- /dev/null
@@ -0,0 +1,54 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t
+// RUN: ld.lld -discard-none -shared %t -o %t2
+// RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+.text
+.Lmyvar:
+.Lmyothervar:
+
+// CHECK:   Section {
+// CHECK:     Name: .strtab
+// CHECK-NEXT:     Type: SHT_STRTAB
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 002E4C6D 796F7468 65727661 72002E4C  |..Lmyothervar..L|
+// CHECK-NEXT:       0010: 6D797661 72005F44 594E414D 494300    |myvar._DYNAMIC.|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+
+// CHECK:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: .Lmyothervar
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: .Lmyvar
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
diff --git a/test/ELF/dont-export-hidden.s b/test/ELF/dont-export-hidden.s
new file mode 100644 (file)
index 0000000..8088c8d
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc %p/Inputs/shared.s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: ld.lld %t2.o %t.so -o %t.exe
+// RUN: llvm-readobj --dyn-symbols %t.exe | FileCheck %s
+
+        .global _start
+_start:
+        .global bar
+        .hidden bar
+bar:
+
+        .global bar2
+bar2:
+
+        .global foo
+foo:
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar2
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
diff --git a/test/ELF/driver-access.test b/test/ELF/driver-access.test
new file mode 100644 (file)
index 0000000..5209483
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86, shell
+# Make sure that LLD works even if the current directory is not writable.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+
+# RUN: mkdir -p %t.dir
+# RUN: chmod 100 %t.dir
+# RUN: cd %t.dir
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: chmod 755 %t.dir
+
+.globl _start
+_start:
+  nop
diff --git a/test/ELF/driver.test b/test/ELF/driver.test
new file mode 100644 (file)
index 0000000..d876218
--- /dev/null
@@ -0,0 +1,60 @@
+# REQUIRES: x86
+
+# RUN: not ld.lld --unknown1 --unknown2 -m foo /no/such/file -lnosuchlib \
+# RUN:   2>&1 | FileCheck -check-prefix=UNKNOWN %s
+
+# UNKNOWN: unknown argument: --unknown1
+# UNKNOWN: unknown argument: --unknown2
+# UNKNOWN: unknown emulation: foo
+# UNKNOWN: cannot open /no/such/file
+# UNKNOWN: unable to find library -lnosuchlib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t -o /no/such/file 2>&1 | FileCheck -check-prefix=MISSING %s
+# MISSING: cannot open output file /no/such/file
+
+# RUN: ld.lld --help 2>&1 | FileCheck -check-prefix=HELP %s
+# HELP: USAGE:
+# HELP: : supported targets:{{.*}} elf
+
+# RUN: ld.lld --version 2>&1 | FileCheck -check-prefix=VERSION %s
+# VERSION: LLD {{.*}} (compatible with GNU linkers)
+
+# RUN: not ld.lld -v 2>&1 | FileCheck -check-prefix=VERSION %s
+
+## Attempt to link DSO with -r
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: not ld.lld -r %t.so %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR %s
+# ERR: attempted static link of dynamic object
+
+## Attempt to use -r and -shared together
+# RUN: not ld.lld -r -shared %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: -r and -shared may not be used together
+
+## Attempt to use -r and --gc-sections together
+# RUN: not ld.lld -r --gc-sections %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: -r and --gc-sections may not be used together
+
+## Attempt to use -r and --icf together
+# RUN: not ld.lld -r --icf=all %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: -r and --icf may not be used together
+
+## Attempt to use -r and -pie together
+# RUN: not ld.lld -r -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: -r and -pie may not be used together
+
+## Attempt to use -shared and -pie together
+# RUN: not ld.lld -shared -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: -shared and -pie may not be used together
+
+## "--output=foo" is equivalent to "-o foo".
+# RUN: not ld.lld %t --output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR7 %s
+# ERR7: cannot open output file /no/such/file
+
+## "-output=foo" is equivalent to "-o utput=foo".
+# RUN: not ld.lld %t -output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR8 %s
+# ERR8: cannot open output file utput=/no/such/file
+
+.globl _start
+_start:
+  nop
diff --git a/test/ELF/dso-undef-size.s b/test/ELF/dso-undef-size.s
new file mode 100644 (file)
index 0000000..5a23556
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/dso-undef-size.s -o %t1.o
+# RUN: ld.lld -shared %t1.o -o %t1.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+# RUN: ld.lld -shared %t2.o %t1.so -o %t2.so
+# RUN: llvm-readobj -symbols -dyn-symbols %t2.so
+
+# CHECK:      Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.text
+.global foo
diff --git a/test/ELF/dso_handle.s b/test/ELF/dso_handle.s
new file mode 100644 (file)
index 0000000..99e2594
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck %s
+# CHECK:    Name: __dso_handle
+# CHECK-NEXT:    Value: 0x0
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Local
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other [
+# CHECK-NEXT:      STV_HIDDEN
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Section: .dynsym
+
+.text
+.global foo, __dso_handle
+foo:
+  lea __dso_handle(%rip),%rax
diff --git a/test/ELF/dt_flags.s b/test/ELF/dt_flags.s
new file mode 100644 (file)
index 0000000..431f83d
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: ld.lld -z now -z nodelete -z nodlopen -z origin -Bsymbolic %t %t.so -o %t1
+# RUN: ld.lld %t %t.so -o %t2
+# RUN: llvm-readobj -dynamic-table %t1 | FileCheck -check-prefix=FLAGS %s
+# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
+
+# FLAGS: DynamicSection [
+# FLAGS:   0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW
+# FLAGS:   0x000000006FFFFFFB FLAGS_1 NOW NODELETE NOOPEN ORIGIN
+# FLAGS: ]
+
+# CHECK: DynamicSection [
+# CHECK-NOT:   0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW
+# CHECK-NOT:   0x000000006FFFFFFB FLAGS_1 NOW NODELETE NOOPEN ORIGIN
+# CHECK: ]
+
+.globl _start
+_start:
diff --git a/test/ELF/dt_tags.s b/test/ELF/dt_tags.s
new file mode 100644 (file)
index 0000000..f2759d6
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
+# RUN: ld.lld -shared %t -o %t.so
+# RUN: ld.lld %t %t.so -o %t.exe
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DSO %s
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=EXE %s
+
+# EXE: DynamicSection [
+# EXE:   0x0000000000000015 DEBUG                0x0
+# EXE: ]
+
+# DSO: DynamicSection [
+# DSO-NOT:   0x0000000000000015 DEBUG                0x0
+# DSO: ]
+
+.globl _start
+_start:
diff --git a/test/ELF/dtrace-r.test b/test/ELF/dtrace-r.test
new file mode 100644 (file)
index 0000000..2b6d885
--- /dev/null
@@ -0,0 +1,8 @@
+RUN: ld.lld -r -o %t.o %p/Inputs/dtrace-r.o
+RUN: llvm-readobj -r %t.o | FileCheck %s
+
+CHECK:      Relocations [
+CHECK-NEXT:   Section ({{.*}}) .rela.text {
+CHECK-NEXT:     0x0 R_X86_64_NONE - 0x0
+CHECK-NEXT:   }
+CHECK-NEXT: ]
diff --git a/test/ELF/duplicated-plt-entry.s b/test/ELF/duplicated-plt-entry.s
new file mode 100644 (file)
index 0000000..4644bed
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/duplicated-plt-entry.s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.so -o %t2.so -shared
+
+// RUN: llvm-readobj -r %t2.so | FileCheck %s
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:       R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+callq bar@PLT
+callq bar@PLT
diff --git a/test/ELF/duplicated-synthetic-sym.s b/test/ELF/duplicated-synthetic-sym.s
new file mode 100644 (file)
index 0000000..cfd8642
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: cd %S
+// RUN: not ld.lld %t.o --format=binary duplicated-synthetic-sym.s -o %t.elf 2>&1 | FileCheck %s
+
+// CHECK: duplicate symbol: _binary_duplicated_synthetic_sym_s_start
+// CHECK: defined at (internal):(.data+0x0)
+
+    .globl  _binary_duplicated_synthetic_sym_s_start
+_binary_duplicated_synthetic_sym_s_start:
+    .long   0
diff --git a/test/ELF/dynamic-got-rela.s b/test/ELF/dynamic-got-rela.s
new file mode 100644 (file)
index 0000000..0aeb6d4
--- /dev/null
@@ -0,0 +1,34 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s -l -section-data %t.so | FileCheck %s
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x[[GOT:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000 00000000                |
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x[[GOT]] R_X86_64_RELATIVE - 0x[[ADDEND:.*]]
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Type: PT_DYNAMIC
+// CHECK-NEXT: Offset: 0x[[ADDEND]]
+// CHECK-NEXT: VirtualAddress: 0x[[ADDEND]]
+// CHECK-NEXT: PhysicalAddress: 0x[[ADDEND]]
+
+cmpq    $0, _DYNAMIC@GOTPCREL(%rip)
diff --git a/test/ELF/dynamic-got.s b/test/ELF/dynamic-got.s
new file mode 100644 (file)
index 0000000..c50c902
--- /dev/null
@@ -0,0 +1,39 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -l -section-data -r %t.so | FileCheck %s
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00200000                |
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
+// CHECK-NEXT:     0x2050 R_386_RELATIVE - 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Type: PT_DYNAMIC
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: VirtualAddress: 0x2000
+// CHECK-NEXT: PhysicalAddress: 0x2000
+
+        calll   .L0$pb
+.L0$pb:
+        popl    %eax
+.Ltmp0:
+        addl    $_GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb), %eax
+        movl    _DYNAMIC@GOT(%eax), %eax
diff --git a/test/ELF/dynamic-list-extern.s b/test/ELF/dynamic-list-extern.s
new file mode 100644 (file)
index 0000000..dfeb31d
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# Test that we can parse multiple externs.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo '{ \
+# RUN:         extern "C" { \
+# RUN:           foo; \
+# RUN:         }; \
+# RUN:         extern "C++" { \
+# RUN:           bar; \
+# RUN:         }; \
+# RUN:       };' > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t.o -shared -o %t.so
diff --git a/test/ELF/dynamic-list.s b/test/ELF/dynamic-list.s
new file mode 100644 (file)
index 0000000..7cd5873
--- /dev/null
@@ -0,0 +1,171 @@
+## There is some bad quoting interaction between lit's internal shell, which is
+## implemented in Python, and the Cygwin implementations of the Unix utilities.
+## Avoid running these tests on Windows for now by requiring a real shell.
+
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check exporting only one symbol.
+# RUN: echo "{ foo1; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+## And now using quoted strings (the output is the same since it does
+## use any wildcard character).
+# RUN: echo "{ \"foo1\"; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+## And now using --export-dynamic-symbol.
+# RUN: ld.lld --export-dynamic-symbol foo1 %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+# RUN: ld.lld --export-dynamic-symbol=foo1 %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo1@
+# CHECK-NEXT:     Value: 0x201000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text (0x4)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+
+## Now export all the foo1, foo2, and foo31 symbols
+# RUN: echo "{ foo1; foo2; foo31; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK2 %s
+# RUN: echo "{ foo1; foo2; };" > %t1.list
+# RUN: echo "{ foo31; };" > %t2.list
+# RUN: ld.lld --dynamic-list %t1.list --dynamic-list %t2.list %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK2:      DynamicSymbols [
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: @
+# CHECK2-NEXT:     Value: 0x0
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Local
+# CHECK2-NEXT:     Type: None
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: Undefined
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo1@
+# CHECK2-NEXT:     Value: 0x201000
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo2@
+# CHECK2-NEXT:     Value: 0x201001
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT:   Symbol {
+# CHECK2-NEXT:     Name: foo31@
+# CHECK2-NEXT:     Value: 0x201002
+# CHECK2-NEXT:     Size: 0
+# CHECK2-NEXT:     Binding: Global (0x1)
+# CHECK2-NEXT:     Type: None (0x0)
+# CHECK2-NEXT:     Other: 0
+# CHECK2-NEXT:     Section: .text (0x4)
+# CHECK2-NEXT:   }
+# CHECK2-NEXT: ]
+
+
+## --export-dynamic overrides --dynamic-list, i.e. --export-dynamic with an
+## incomplete dynamic-list still exports everything.
+# RUN: echo "{ foo2; };" > %t.list
+# RUN: ld.lld --dynamic-list %t.list --export-dynamic %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK3 %s
+
+## The same with --export-dynamic-symbol.
+# RUN: ld.lld --export-dynamic-symbol=foo2 --export-dynamic %t %t2.so -o %t.exe
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK3 %s
+
+# CHECK3:      DynamicSymbols [
+# CHECK3-NEXT:   Symbol {
+# CHECK3-NEXT:     Name: @
+# CHECK3-NEXT:     Value: 0x0
+# CHECK3-NEXT:     Size: 0
+# CHECK3-NEXT:     Binding: Local
+# CHECK3-NEXT:     Type: None
+# CHECK3-NEXT:     Other: 0
+# CHECK3-NEXT:     Section: Undefined
+# CHECK3-NEXT:   }
+# CHECK3-NEXT:   Symbol {
+# CHECK3-NEXT:     Name: _start@
+# CHECK3-NEXT:     Value: 0x201003
+# CHECK3-NEXT:     Size: 0
+# CHECK3-NEXT:     Binding: Global (0x1)
+# CHECK3-NEXT:     Type: None (0x0)
+# CHECK3-NEXT:     Other: 0
+# CHECK3-NEXT:     Section: .text (0x4)
+# CHECK3-NEXT:   }
+# CHECK3-NEXT:   Symbol {
+# CHECK3-NEXT:     Name: foo1@
+# CHECK3-NEXT:     Value: 0x201000
+# CHECK3-NEXT:     Size: 0
+# CHECK3-NEXT:     Binding: Global (0x1)
+# CHECK3-NEXT:     Type: None (0x0)
+# CHECK3-NEXT:     Other: 0
+# CHECK3-NEXT:     Section: .text (0x4)
+# CHECK3-NEXT:   }
+# CHECK3-NEXT:   Symbol {
+# CHECK3-NEXT:     Name: foo2@
+# CHECK3-NEXT:     Value: 0x201001
+# CHECK3-NEXT:     Size: 0
+# CHECK3-NEXT:     Binding: Global (0x1)
+# CHECK3-NEXT:     Type: None (0x0)
+# CHECK3-NEXT:     Other: 0
+# CHECK3-NEXT:     Section: .text (0x4)
+# CHECK3-NEXT:   }
+# CHECK3-NEXT:   Symbol {
+# CHECK3-NEXT:     Name: foo31@
+# CHECK3-NEXT:     Value: 0x201002
+# CHECK3-NEXT:     Size: 0
+# CHECK3-NEXT:     Binding: Global (0x1)
+# CHECK3-NEXT:     Type: None (0x0)
+# CHECK3-NEXT:     Other: 0
+# CHECK3-NEXT:     Section: .text (0x4)
+# CHECK3-NEXT:   }
+# CHECK3-NEXT: ]
+
+.globl foo1
+foo1:
+  ret
+
+.globl foo2
+foo2:
+  ret
+
+.globl foo31
+foo31:
+  ret
+
+.globl _start
+_start:
+  retq
diff --git a/test/ELF/dynamic-reloc-in-ro.s b/test/ELF/dynamic-reloc-in-ro.s
new file mode 100644 (file)
index 0000000..23b068f
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against local symbol in readonly segment
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
+
+foo:
+.quad foo
diff --git a/test/ELF/dynamic-reloc-index.s b/test/ELF/dynamic-reloc-index.s
new file mode 100644 (file)
index 0000000..47e8c6c
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+
+// We used to record the wrong symbol index for this test
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x202018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .global foobar
+foobar:
+        .global zedx
+zedx:
+        .global _start
+_start:
+.quad bar
diff --git a/test/ELF/dynamic-reloc-weak.s b/test/ELF/dynamic-reloc-weak.s
new file mode 100644 (file)
index 0000000..b4da2e5
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc-weak.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -r  %t | FileCheck %s
+// REQUIRES: x86
+
+        .globl _start
+_start:
+        .type sym1,@function
+        .weak sym1
+        .long sym1@gotpcrel
+
+        .type sym2,@function
+        .weak sym2
+        .long sym2@plt
+
+        .type sym3,@function
+        .weak sym3
+        .quad sym3
+
+        .type sym4,@function
+        .weak sym4
+        .quad sym4
+
+// Test that we produce dynamic relocation for every weak undefined symbol
+// we found.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_GLOB_DAT sym1 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_JUMP_SLOT sym2 0x0
+// CHECK-NEXT:     0x{{.*}} R_X86_64_JUMP_SLOT sym3 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/dynamic-reloc.s b/test/ELF/dynamic-reloc.s
new file mode 100644 (file)
index 0000000..939093c
--- /dev/null
@@ -0,0 +1,65 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc.s -o %t3.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t3.o %t2.so -o %t
+// RUN: llvm-readobj -dynamic-table -r --expand-relocs -s %t | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Index: 1
+// CHECK-NEXT: Name: .dynsym
+
+// CHECK:      Name: .rela.plt
+// CHECK-NEXT: Type: SHT_RELA
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[RELAADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[RELASIZE:.*]]
+// CHECK-NEXT: Link: 1
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 24
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x201000
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: 0x202018
+// CHECK-NEXT:       Type: R_X86_64_JUMP_SLOT
+// CHECK-NEXT:       Symbol: bar
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: DynamicSection [
+// CHECK-NEXT:  Tag                Type                 Name/Value
+// CHECK-NEXT:  0x0000000000000001 NEEDED               Shared library: [{{.*}}2.so]
+// CHECK-NEXT:  0x0000000000000015 DEBUG                0x0
+// CHECK-NEXT:  0x0000000000000017 JMPREL
+// CHECK-NEXT:  0x0000000000000002 PLTRELSZ             24 (bytes)
+// CHECK-NEXT:  0x0000000000000003 PLTGOT
+// CHECK-NEXT:  0x0000000000000014 PLTREL               RELA
+// CHECK-NEXT:  0x0000000000000006 SYMTAB
+// CHECK-NEXT:  0x000000000000000B SYMENT               24 (bytes)
+// CHECK-NEXT:  0x0000000000000005 STRTAB
+// CHECK-NEXT:  0x000000000000000A STRSZ
+// CHECK-NEXT:  0x0000000000000004 HASH
+// CHECK-NEXT:  0x0000000000000000 NULL                 0x0
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+.quad bar + 0x42
+.weak foo
+.quad foo
+call main
diff --git a/test/ELF/dynamic.s b/test/ELF/dynamic.s
new file mode 100644 (file)
index 0000000..0ed7abc
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t.o
+
+## Check that _DYNAMIC symbol is created when creating dynamic output,
+## and has hidden visibility and address equal to .dynamic section.
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -sections -symbols %t.so | FileCheck %s
+# CHECK:      Section {
+# CHECK:        Index: 5
+# CHECK:        Name: .dynamic
+# CHECK-NEXT:   Type: SHT_DYNAMIC
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x[[ADDR:.*]]
+# CHECK-NEXT:   Offset: 0x1000
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK:      Symbols [
+# CHECK:        Symbol {
+# CHECK:          Name: _DYNAMIC
+# CHECK-NEXT:     Value: 0x[[ADDR]]
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other [ (0x2)
+# CHECK-NEXT:       STV_HIDDEN
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Section: .dynamic
+# CHECK-NEXT:   }
+
+# RUN: ld.lld %t.o -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=NODYN %s
+# NODYN:    Symbols [
+# NODYN-NOT: Name: _DYNAMIC
+# NODYN:    ]
+
+.globl _start
+_start:
diff --git a/test/ELF/dynsym-pie.s b/test/ELF/dynsym-pie.s
new file mode 100644 (file)
index 0000000..9d3a9ff
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld -pie %t -o %t.out
+# RUN: llvm-readobj -t -dyn-symbols %t.out | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name: @
+# CHECK-NEXT:    Value: 0x0
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Local
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: Undefined
+# CHECK-NEXT:  }
+# CHECK-NEXT: ]
+
+.text
+.globl _start
+_start:
+
+.global default
+default:
+
+.global protected
+protected:
+
+.global hidden
+hidden:
+
+.global internal
+internal:
+
+.global protected_with_hidden
+.protected
+protected_with_hidden:
diff --git a/test/ELF/early-exit-for-bad-paths.s b/test/ELF/early-exit-for-bad-paths.s
new file mode 100644 (file)
index 0000000..03462f5
--- /dev/null
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: not ld.lld %t.o -o does_not_exist/output 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=NO-DIR-OUTPUT,CHECK
+# RUN: not ld.lld %t.o -o %s/dir_is_a_file 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=DIR-IS-OUTPUT,CHECK
+
+# RUN: echo "OUTPUT(\"does_not_exist/output\")" > %t.script
+# RUN: not ld.lld %t.o %t.script 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=NO-DIR-OUTPUT,CHECK
+# RUN: echo "OUTPUT(\"%s/dir_is_a_file\")" > %t.script
+# RUN: not ld.lld %t.o %t.script 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=DIR-IS-OUTPUT,CHECK
+
+# RUN: not ld.lld %t.o -o %t -Map=does_not_exist/output 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=NO-DIR-MAP,CHECK
+# RUN: not ld.lld %t.o -o %t -Map=%s/dir_is_a_file 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=DIR-IS-MAP,CHECK
+
+# NO-DIR-OUTPUT: error: cannot open output file does_not_exist/output:
+# DIR-IS-OUTPUT: error: cannot open output file {{.*}}/dir_is_a_file:
+# NO-DIR-MAP: error: cannot open map file does_not_exist/output:
+# DIR-IS-MAP: error: cannot open map file {{.*}}/dir_is_a_file:
+
+# We should exit before doing the actual link. If an undefined symbol error is
+# discovered we haven't bailed out early as expected.
+# CHECK-NOT: undefined_symbol
+
+# RUN: not ld.lld %t.o -o / 2>&1 | FileCheck %s -check-prefixes=ROOT,CHECK
+# ROOT: error: cannot open output file /
+
+  .globl _start
+_start:
+  call undefined_symbol
diff --git a/test/ELF/edata-etext.s b/test/ELF/edata-etext.s
new file mode 100644 (file)
index 0000000..3b0ba49
--- /dev/null
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -t -section-headers %t | FileCheck %s
+
+## This checks that:
+## 1) Address of _etext is the first location after the last read-only loadable segment.
+## 2) Address of _edata points to the end of the last non SHT_NOBITS section.
+##    That is how gold/bfd do. At the same time specs says: "If the address of _edata is
+##    greater than the address of _etext, the address of _end is same as the address
+##    of _edata." (https://docs.oracle.com/cd/E53394_01/html/E54766/u-etext-3c.html).
+## 3) Address of _end is different from _edata because of 2.
+# CHECK:      Sections:
+# CHECK-NEXT:  Idx Name          Size      Address          Type
+# CHECK-NEXT:    0               00000000 0000000000000000
+# CHECK-NEXT:    1 .text         00000001 0000000000201000 TEXT DATA
+# CHECK-NEXT:    2 .data         00000002 0000000000202000 DATA
+# CHECK-NEXT:    3 .bss          00000006 0000000000202004 BSS
+# CHECK:      SYMBOL TABLE:
+# CHECK-NEXT:  0000000000000000         *UND* 00000000
+# CHECK-NEXT:  0000000000202002         .data 00000000 _edata
+# CHECK-NEXT:  000000000020200a         .data 00000000 _end
+# CHECK-NEXT:  0000000000201001         .text 00000000 _etext
+# CHECK-NEXT:  0000000000201000         .text 00000000 _start
+
+# RUN: ld.lld -r %t.o -o %t2
+# RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=RELOCATABLE
+# RELOCATABLE:       0000000000000000 *UND* 00000000 _edata
+# RELOCATABLE-NEXT:  0000000000000000 *UND* 00000000 _end
+# RELOCATABLE-NEXT:  0000000000000000 *UND* 00000000 _etext
+
+.global _start,_end,_etext,_edata
+.text
+_start:
+  nop
+.data
+  .word 1
+.bss
+  .align 4
+  .space 6
diff --git a/test/ELF/eh-align-cie.s b/test/ELF/eh-align-cie.s
new file mode 100644 (file)
index 0000000..343dea5
--- /dev/null
@@ -0,0 +1,57 @@
+// REQUIRES: x86
+
+       .cfi_startproc
+       .cfi_personality 0x1b, bar
+       .cfi_endproc
+
+.global bar
+.hidden bar
+bar:
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-readobj -s -section-data %t.o | FileCheck --check-prefix=OBJ %s
+
+// Check the size of the CIE (0x18 + 4) an FDE (0x10 + 4)
+// OBJ: Name: .eh_frame
+// OBJ-NEXT:    Type:
+// OBJ-NEXT:    Flags [
+// OBJ-NEXT:      SHF_ALLOC
+// OBJ-NEXT:    ]
+// OBJ-NEXT:    Address:
+// OBJ-NEXT:    Offset:
+// OBJ-NEXT:    Size:
+// OBJ-NEXT:    Link:
+// OBJ-NEXT:    Info:
+// OBJ-NEXT:    AddressAlignment:
+// OBJ-NEXT:    EntrySize:
+// OBJ-NEXT:    SectionData (
+// OBJ-NEXT:      0000: 18000000 00000000 017A5052 00017810
+// OBJ-NEXT:      0010: 061B0000 00001B0C 07089001 10000000
+// OBJ-NEXT:      0020: 20000000 00000000 00000000 00000000
+// OBJ-NEXT:    )
+
+
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+// Check that the size of the CIE was changed to (0x1C + 4) and the FDE one was
+// changed to (0x14 + 4)
+
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type:
+// CHECK-NEXT: Flags
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 1C000000 00000000 017A5052 00017810
+// CHECK-NEXT:   0010: 061BF60D 00001B0C 07089001 00000000
+// CHECK-NEXT:   0020: 14000000 24000000 E00D0000 00000000
+// CHECK-NEXT:   0030: 00000000 00000000
+// CHECK-NEXT: )
diff --git a/test/ELF/eh-frame-begin-end.s b/test/ELF/eh-frame-begin-end.s
new file mode 100644 (file)
index 0000000..a7f0bb7
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=amd64-unknown-openbsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=amd64-unknown-openbsd %p/Inputs/eh-frame-end.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t
+// RUN: llvm-readobj -sections %t | FileCheck %s
+
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x200120
+// CHECK-NEXT: Offset: 0x120
+// CHECK-NEXT: Size: 4
+
+       .section ".eh_frame", "a", @progbits
+__EH_FRAME_BEGIN__:
diff --git a/test/ELF/eh-frame-dyn-rel.s b/test/ELF/eh-frame-dyn-rel.s
new file mode 100644 (file)
index 0000000..289e6c0
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o %t.o -o %t -shared 2>&1 | FileCheck %s
+
+// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo
+// CHECK: >>> defined in {{.*}}.o
+// CHECK: >>> referenced by {{.*}}.o:(.eh_frame+0x12)
+
+.section bar,"axG",@progbits,foo,comdat
+.cfi_startproc
+.cfi_personality 0x8c, foo
+.cfi_endproc
diff --git a/test/ELF/eh-frame-gc.s b/test/ELF/eh-frame-gc.s
new file mode 100644 (file)
index 0000000..b2e21f4
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+# RUN: ld.lld -shared --gc-sections %t.o -o %t
+# RUN: llvm-readobj  -s %t | FileCheck %s
+
+## Check that section containing personality is
+## not garbage collected.
+# CHECK: Sections [
+# CHECK: Name: .test_personality_section
+
+.text
+.globl foo
+.type foo,@function
+foo:
+ .cfi_startproc
+ .cfi_personality 155, DW.ref.__gxx_personality_v0
+ .cfi_endproc
+
+.section .test_personality_section
+DW.ref.__gxx_personality_v0:
diff --git a/test/ELF/eh-frame-gc2.s b/test/ELF/eh-frame-gc2.s
new file mode 100644 (file)
index 0000000..9cf0d08
--- /dev/null
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld --gc-sections %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+
+// Test that the we don't gc the personality function.
+// CHECK: Name: .foobar
+
+       .globl  _start
+_start:
+       .cfi_startproc
+       .cfi_personality 3, foobar
+       .cfi_endproc
+        .section .foobar,"ax"
+foobar:
diff --git a/test/ELF/eh-frame-hdr-abs-fde.s b/test/ELF/eh-frame-hdr-abs-fde.s
new file mode 100644 (file)
index 0000000..c3dc862
--- /dev/null
@@ -0,0 +1,33 @@
+# Check reading PC values of FDEs and writing lookup table in the .eh_frame_hdr
+# if CIE augmentation string has 'L' token and PC values are encoded using
+# absolute (not relative) format.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld --eh-frame-hdr %t.o -o %t
+# RUN: llvm-objdump -s -dwarf=frames %t | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Contents of section .eh_frame_hdr:
+# CHECK-NEXT:  10128 011b033b 00000010 00000001 0000fed8
+#                                               ^-- 0x20000 - 0x10138
+#                                                   .text   - .eh_frame_hdr
+# CHECK-NEXT:  10138 0000002c
+# CHECK:      Contents of section .text:
+# CHECK-NEXT:  20000 00000000
+
+# CHECK: Augmentation:          "zLR"
+# CHECK: Augmentation data:     00 0B
+#                                  ^-- DW_EH_PE_udata4 | DW_EH_PE_signed
+
+       .text
+  .globl __start
+__start:
+       .cfi_startproc
+  .cfi_lsda 0, _ex
+  nop
+       .cfi_endproc
+
+  .data
+_ex:
+  .word 0
diff --git a/test/ELF/eh-frame-hdr-augmentation.s b/test/ELF/eh-frame-hdr-augmentation.s
new file mode 100644 (file)
index 0000000..618f5e1
--- /dev/null
@@ -0,0 +1,38 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t -shared
+// RUN: llvm-objdump --dwarf=frames %t | FileCheck %s
+
+// CHECK: .eh_frame contents:
+
+// CHECK:      00000000 0000001c ffffffff CIE
+// CHECK-NEXT:   Version:                       1
+// CHECK-NEXT:   Augmentation:             "zPLR"
+// CHECK-NEXT:   Code alignment factor: 1
+// CHECK-NEXT:   Data alignment factor: -8
+// CHECK-NEXT:   Return address column: 16
+// CHECK-NEXT:   Augmentation data:
+
+// CHECK:      DW_CFA_def_cfa:  reg7 +8
+// CHECK-NEXT: DW_CFA_offset:   reg16 -8
+// CHECK-NEXT: DW_CFA_nop:
+// CHECK-NEXT: DW_CFA_nop:
+
+// CHECK:      00000020 00000014 00000024 FDE cie=00000024 pc=00000d98...00000d98
+// CHECK-NEXT:   DW_CFA_nop:
+// CHECK-NEXT:   DW_CFA_nop:
+// CHECK-NEXT:   DW_CFA_nop:
+
+        .cfi_startproc
+        .cfi_personality 0x9b, g
+        .cfi_lsda 0x1b, h
+        .cfi_endproc
+
+        .global g
+        .hidden g
+g:
+
+        .global h
+        .hidden h
+h:
+
diff --git a/test/ELF/eh-frame-hdr-icf.s b/test/ELF/eh-frame-hdr-icf.s
new file mode 100644 (file)
index 0000000..1b42285
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --eh-frame-hdr
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK: Contents of section .eh_frame_hdr:
+# CHECK-NEXT: 200158 011b033b 1c000000 01000000 a80e0000
+#                                      ^ FDE count
+# CHECK-NEXT: 200168 38000000 00000000 00000000
+#                    ^ FDE for f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  .cfi_startproc
+  ret
+  .cfi_endproc
+
+.section .text.f2, "ax"
+f2:
+  .cfi_startproc
+  ret
+  .cfi_endproc
diff --git a/test/ELF/eh-frame-hdr-no-out2.s b/test/ELF/eh-frame-hdr-no-out2.s
new file mode 100644 (file)
index 0000000..0eeb0ea
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t
+// RUN: llvm-readobj -s -program-headers %t | FileCheck %s --check-prefix=NOHDR
+
+.section foo,"ax",@progbits
+ nop
+
+.text
+.globl _start
+_start:
+
+// There is no .eh_frame section,
+// therefore .eh_frame_hdr also not created.
+// NOHDR:       Sections [
+// NOHDR-NOT:    Name: .eh_frame
+// NOHDR-NOT:    Name: .eh_frame_hdr
+// NOHDR:      ProgramHeaders [
+// NOHDR-NOT:   PT_GNU_EH_FRAME
diff --git a/test/ELF/eh-frame-hdr.s b/test/ELF/eh-frame-hdr.s
new file mode 100644 (file)
index 0000000..35c14a4
--- /dev/null
@@ -0,0 +1,126 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=NOHDR
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t
+// RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t | FileCheck %s --check-prefix=HDR
+// RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=HDRDISASM
+
+.section foo,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section bar,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.text
+.globl _start
+_start:
+
+// NOHDR:       Sections [
+// NOHDR-NOT:    Name: .eh_frame_hdr
+// NOHDR:      ProgramHeaders [
+// NOHDR-NOT:   PT_GNU_EH_FRAME
+
+//HDRDISASM:      Disassembly of section foo:
+//HDRDISASM-NEXT: foo:
+//HDRDISASM-NEXT:    201000: 90 nop
+//HDRDISASM-NEXT: Disassembly of section bar:
+//HDRDISASM-NEXT: bar:
+//HDRDISASM-NEXT:    201001: 90 nop
+//HDRDISASM-NEXT: Disassembly of section dah:
+//HDRDISASM-NEXT: dah:
+//HDRDISASM-NEXT:    201002: 90 nop
+
+// HDR:       Section {
+// HDR:         Index:
+// HDR:         Name: .eh_frame_hdr
+// HDR-NEXT:    Type: SHT_PROGBITS
+// HDR-NEXT:    Flags [
+// HDR-NEXT:      SHF_ALLOC
+// HDR-NEXT:    ]
+// HDR-NEXT:    Address: 0x200158
+// HDR-NEXT:    Offset: 0x158
+// HDR-NEXT:    Size: 36
+// HDR-NEXT:    Link: 0
+// HDR-NEXT:    Info: 0
+// HDR-NEXT:    AddressAlignment: 1
+// HDR-NEXT:    EntrySize: 0
+// HDR-NEXT:    SectionData (
+// HDR-NEXT:      0000: 011B033B 24000000 03000000 A80E0000
+// HDR-NEXT:      0010: 40000000 A90E0000 58000000 AA0E0000
+// HDR-NEXT:      0020: 70000000
+// HDR-NEXT:    )
+//              Header (always 4 bytes): 0x011B033B
+//                 24000000 = .eh_frame(0x200180) - .eh_frame_hdr(0x200158) - 4
+//                 03000000 = 3 = the number of FDE pointers in the table.
+//              Entry(1): A80E0000 40000000
+//                 480E0000 = 0x201000 - .eh_frame_hdr(0x200158) = 0xEA8
+//                 40000000 = address of FDE(1) - .eh_frame_hdr(0x200158) =
+//                    = .eh_frame(0x200180) + 24 - 0x200158 = 0x40
+//              Entry(2): A90E0000 58000000
+//                 A90E0000 = 0x201001 - .eh_frame_hdr(0x200158) = 0xEA9
+//                 58000000 = address of FDE(2) - .eh_frame_hdr(0x200158) =
+//                    = .eh_frame(0x200180) + 24 + 24 - 0x200158 = 0x58
+//              Entry(3): AA0E0000 70000000
+//                 AA0E0000 = 0x201002 - .eh_frame_hdr(0x200158) = 0xEAA
+//                 70000000 = address of FDE(3) - .eh_frame_hdr(0x200158) =
+//                    = .eh_frame(0x200180) + 24 + 24 + 24 - 0x200158 = 0x70
+// HDR-NEXT:  }
+// HDR-NEXT:  Section {
+// HDR-NEXT:    Index:
+// HDR-NEXT:    Name: .eh_frame
+// HDR-NEXT:    Type: SHT_PROGBITS
+// HDR-NEXT:    Flags [
+// HDR-NEXT:      SHF_ALLOC
+// HDR-NEXT:    ]
+// HDR-NEXT:    Address: 0x200180
+// HDR-NEXT:    Offset: 0x180
+// HDR-NEXT:    Size: 96
+// HDR-NEXT:    Link: 0
+// HDR-NEXT:    Info: 0
+// HDR-NEXT:    AddressAlignment: 8
+// HDR-NEXT:    EntrySize: 0
+// HDR-NEXT:    SectionData (
+// HDR-NEXT:      0000: 14000000 00000000 017A5200 01781001
+// HDR-NEXT:      0010: 1B0C0708 90010000 14000000 1C000000
+// HDR-NEXT:      0020: 600E0000 01000000 00000000 00000000
+// HDR-NEXT:      0030: 14000000 34000000 490E0000 01000000
+// HDR-NEXT:      0040: 00000000 00000000 14000000 4C000000
+// HDR-NEXT:      0050: 320E0000 01000000 00000000 00000000
+// HDR-NEXT:    )
+//            CIE: 14000000 00000000 017A5200 01781001 1B0C0708 90010000
+//            FDE(1): 14000000 1C000000 600E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x600E0000) = 0x200180 + 0x0020 = 0x2001A0
+//                    The starting address to which this FDE applies = 0xE60 + 0x2001A0 = 0x201000
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+//            FDE(2): 14000000 34000000 490E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x490E0000) = 0x200180 + 0x0038 = 0x2001B8
+//                    The starting address to which this FDE applies = 0xE49 + 0x2001B8 = 0x201001
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+//            FDE(3): 14000000 4C000000 320E0000 01000000 00000000 00000000
+//                    address of data (starts with 0x320E0000) = 0x200180 + 0x0050 = 0x2001D0
+//                    The starting address to which this FDE applies = 0xE5A + 0x2001D0 = 0x201002
+//                    The number of bytes after the start address to which this FDE applies = 0x01000000 = 1
+// HDR-NEXT:  }
+// HDR:     ProgramHeaders [
+// HDR:      ProgramHeader {
+// HDR:       Type: PT_GNU_EH_FRAME
+// HDR-NEXT:   Offset: 0x158
+// HDR-NEXT:   VirtualAddress: 0x200158
+// HDR-NEXT:   PhysicalAddress: 0x200158
+// HDR-NEXT:   FileSize: 36
+// HDR-NEXT:   MemSize: 36
+// HDR-NEXT:   Flags [
+// HDR-NEXT:     PF_R
+// HDR-NEXT:   ]
+// HDR-NEXT:   Alignment: 1
+// HDR-NEXT: }
diff --git a/test/ELF/eh-frame-marker.s b/test/ELF/eh-frame-marker.s
new file mode 100644 (file)
index 0000000..30bac46
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t.so -shared
+// RUN: llvm-readobj -t -s %t.so | FileCheck %s
+// We used to crash on this.
+
+// CHECK:      Name: .eh_frame_hdr
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:  [[ADDR:.*]]
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: [[ADDR]]
+
+        .section .eh_frame
+foo:
+        .long 0
diff --git a/test/ELF/eh-frame-merge.s b/test/ELF/eh-frame-merge.s
new file mode 100644 (file)
index 0000000..addbb3f
--- /dev/null
@@ -0,0 +1,58 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %t.o -o %t -shared
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+        .section       foo,"ax",@progbits
+       .cfi_startproc
+        nop
+       .cfi_endproc
+
+        .section       bar,"axG",@progbits,foo,comdat
+        .cfi_startproc
+        nop
+        nop
+       .cfi_endproc
+
+// FIXME: We could really use a .eh_frame parser.
+// The intention is to show that:
+// * There is only one copy of the CIE
+// * There are two copies of the first FDE
+// * There is only one copy of the second FDE
+
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 96
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 14000000 00000000 017A5200 01781001  |
+// CHECK-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000  |
+// CHECK-NEXT: 0020: E80D0000 01000000 00000000 00000000  |
+// CHECK-NEXT: 0030: 14000000 34000000 D20D0000 02000000  |
+// CHECK-NEXT: 0040: 00000000 00000000 14000000 4C000000  |
+// CHECK-NEXT: 0050: B90D0000 01000000 00000000 00000000  |
+// CHECK-NEXT: )
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1002
diff --git a/test/ELF/eh-frame-multilpe-cie.s b/test/ELF/eh-frame-multilpe-cie.s
new file mode 100644 (file)
index 0000000..12781ff
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t.so -shared
+// We would fail to parse multiple cies in the same file.
+
+        .cfi_startproc
+        .cfi_personality 0x9b, foo
+        .cfi_endproc
+
+        .cfi_startproc
+        .cfi_endproc
+
+foo:
diff --git a/test/ELF/eh-frame-plt.s b/test/ELF/eh-frame-plt.s
new file mode 100644 (file)
index 0000000..e84d93c
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.so -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+
+       .globl  _start
+_start:
+       .cfi_startproc
+       .cfi_personality 3, bar
+       .cfi_endproc
+
+// CHECK:      Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:   R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/eh-frame-rel.s b/test/ELF/eh-frame-rel.s
new file mode 100644 (file)
index 0000000..a417dc1
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %t.o -o %t -shared
+// We used to try to read the relocations as RELA and error out
+
+       .cfi_startproc
+       .cfi_endproc
diff --git a/test/ELF/eh-frame-type.test b/test/ELF/eh-frame-type.test
new file mode 100644 (file)
index 0000000..7562997
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t -shared
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK:      Name: .eh_frame
+# CHECK-NEXT: Type: SHT_PROGBITS
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
diff --git a/test/ELF/ehdr_start.s b/test/ELF/ehdr_start.s
new file mode 100644 (file)
index 0000000..94e0fed
--- /dev/null
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck %s
+# CHECK:    Name: __ehdr_start (1)
+# CHECK-NEXT:    Value: 0x200000
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Local (0x0)
+# CHECK-NEXT:    Type: None (0x0)
+# CHECK-NEXT:    Other [ (0x2)
+# CHECK-NEXT:      STV_HIDDEN (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Section: .text (0x1)
+
+# CHECK:    Name: __executable_start
+# CHECK-NEXT:    Value: 0x200000
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Local
+# CHECK-NEXT:    Type: None
+# CHECK-NEXT:    Other [
+# CHECK-NEXT:      STV_HIDDEN
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Section: .text
+
+.text
+.global _start, __ehdr_start
+_start:
+  .quad __ehdr_start
+  .quad __executable_start
+
+# RUN: ld.lld -r %t.o -o %t.r
+# RUN: llvm-readobj -symbols %t.r | FileCheck %s --check-prefix=RELOCATABLE
+
+# RELOCATABLE:    Name: __ehdr_start (1)
+# RELOCATABLE-NEXT:    Value: 0x0
+# RELOCATABLE-NEXT:    Size: 0
+# RELOCATABLE-NEXT:    Binding: Global (0x1)
+# RELOCATABLE-NEXT:    Type: None (0x0)
+# RELOCATABLE-NEXT:    Other: 0
+# RELOCATABLE-NEXT:    Section: Undefined (0x0)
diff --git a/test/ELF/ehframe-relocation.s b/test/ELF/ehframe-relocation.s
new file mode 100644 (file)
index 0000000..0213b1b
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/ehframe-relocation.s  -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+// CHECK:      Name: .eh_frame
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x200120
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 48
+// CHECK-NOT: .eh_frame
+
+// 0x200120 = 2097440
+// 0x200120 + 5 = 2097445
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT:   201000: {{.*}} movq 2097440, %rax
+// DISASM-NEXT:   201008: {{.*}} movq 2097445, %rax
+
+.section .eh_frame,"ax",@unwind
+
+.section .text
+.globl _start
+_start:
+ movq .eh_frame, %rax
+ movq .eh_frame + 5, %rax
diff --git a/test/ELF/emit-relocs-merge.s b/test/ELF/emit-relocs-merge.s
new file mode 100644 (file)
index 0000000..c700c33
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --emit-relocs %t.o -o %t.so -shared
+# RUN: llvm-readobj -r %t.so | FileCheck %s
+
+# CHECK:       Relocations [
+# CHECK-NEXT:    Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x1000 R_X86_64_64 zed 0x0
+# CHECK-NEXT:     0x1008 R_X86_64_64 zed 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section ({{.*}}) .rela.data.foo {
+# CHECK-NEXT:     0x1000 R_X86_64_64 zed 0x0
+# CHECK-NEXT:     0x1008 R_X86_64_64 zed 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.section        .data.foo,"aw",%progbits
+.quad zed
+.section        .data.bar,"aw",%progbits
+.quad zed
diff --git a/test/ELF/emit-relocs-shared.s b/test/ELF/emit-relocs-shared.s
new file mode 100644 (file)
index 0000000..7a0d791
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --emit-relocs %t.o -o %t.so -shared
+# RUN: llvm-readobj -r %t.so | FileCheck %s
+
+.data
+.quad foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (4) .rela.dyn {
+# CHECK-NEXT:     0x1000 R_X86_64_64 foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section (8) .rela.data {
+# CHECK-NEXT:     0x1000 R_X86_64_64 foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/emit-relocs.s b/test/ELF/emit-relocs.s
new file mode 100644 (file)
index 0000000..fd9722f
--- /dev/null
@@ -0,0 +1,106 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld --emit-relocs %t1.o -o %t
+# RUN: llvm-readobj -t -r -s %t | FileCheck %s
+
+## Check single dash form.
+# RUN: ld.lld -emit-relocs %t1.o -o %t1
+# RUN: llvm-readobj -t -r -s %t1 | FileCheck %s
+
+## Check alias.
+# RUN: ld.lld -q %t1.o -o %t2
+# RUN: llvm-readobj -t -r -s %t2 | FileCheck %s
+
+# CHECK:      Section {
+# CHECK:        Index: 2
+# CHECK-NEXT:   Name: .rela.text
+# CHECK-NEXT:   Type: SHT_RELA
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_INFO_LINK
+# CHECK-NEXT:   ]
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.text {
+# CHECK-NEXT:     0x201002 R_X86_64_32 .text 0x1
+# CHECK-NEXT:     0x201007 R_X86_64_PLT32 fn 0xFFFFFFFFFFFFFFFC
+# CHECK-NEXT:     0x20100E R_X86_64_32 .text 0xD
+# CHECK-NEXT:     0x201013 R_X86_64_PLT32 fn2 0xFFFFFFFFFFFFFFFC
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: bar
+# CHECK-NEXT:     Value: 0x201001
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value: 0x20100D
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value: 0x201000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: Section
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: fn
+# CHECK-NEXT:     Value: 0x201000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Function
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: fn2
+# CHECK-NEXT:     Value: 0x20100C
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Function
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.section .text,"ax",@progbits,unique,0
+.globl fn
+.type fn,@function
+fn:
+ nop
+
+bar:
+  movl $bar, %edx
+  callq fn@PLT
+  nop
+
+.section .text,"ax",@progbits,unique,1
+.globl fn2
+.type fn2,@function
+fn2:
+ nop
+
+foo:
+  movl $foo, %edx
+  callq fn2@PLT
+  nop
diff --git a/test/ELF/empty-archive.s b/test/ELF/empty-archive.s
new file mode 100644 (file)
index 0000000..ffb0a78
--- /dev/null
@@ -0,0 +1,3 @@
+// RUN: llvm-ar rc %t.a
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o %t.a -o t
diff --git a/test/ELF/empty-pt-load.s b/test/ELF/empty-pt-load.s
new file mode 100644 (file)
index 0000000..4074b63
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -l --elf-output-style=GNU %t.so | FileCheck %s
+
+// Test that we don't create an empty executable PT_LOAD.
+
+// CHECK:      PHDR    {{.*}} R   0x8
+// CHECK-NEXT: LOAD    {{.*}} R   0x1000
+// CHECK-NEXT: LOAD    {{.*}} RW  0x1000
+// CHECK-NEXT: DYNAMIC {{.*}} RW  0x8
diff --git a/test/ELF/empty-ver.s b/test/ELF/empty-ver.s
new file mode 100644 (file)
index 0000000..3412f31
--- /dev/null
@@ -0,0 +1,43 @@
+// REQUIRES: x86
+// RUN: mkdir -p %t.dir
+// RUN: cd %t.dir
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o t.so -shared -version-script %p/Inputs/empty-ver.ver
+// RUN: llvm-readobj -s -section-data -version-info t.so | FileCheck %s
+
+// CHECK:      Name: .dynstr
+// CHECK-NEXT: Type: SHT_STRTAB
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 14
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00666F6F 00742E73 6F007665 7200      |.foo.t.so.ver.|
+// CHECK-NEXT: )
+
+// CHECK:      Version symbols {
+// CHECK-NEXT:   Section Name:
+// CHECK-NEXT:   Address:
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   Link:
+// CHECK-NEXT:   Symbols [
+// CHECK-NEXT:     Symbol {
+// CHECK-NEXT:       Version: 0
+// CHECK-NEXT:       Name: @
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Symbol {
+// CHECK-NEXT:       Version: 2
+// CHECK-NEXT:       Name: foo@ver
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ]
+// CHECK-NEXT: }
+
+
+.global foo@ver
+foo@ver:
diff --git a/test/ELF/emulation.s b/test/ELF/emulation.s
new file mode 100644 (file)
index 0000000..05efd0b
--- /dev/null
@@ -0,0 +1,360 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %tx64
+# RUN: ld.lld -m elf_amd64_fbsd %tx64 -o %t2x64
+# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=AMD64 %s
+# RUN: ld.lld %tx64 -o %t3x64
+# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=AMD64 %s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.sysv
+# RUN: ld.lld -m elf_amd64_fbsd %t.sysv -o %t.freebsd
+# RUN: llvm-readobj -file-headers %t.freebsd | FileCheck --check-prefix=AMD64 %s
+# AMD64:      ElfHeader {
+# AMD64-NEXT:   Ident {
+# AMD64-NEXT:     Magic: (7F 45 4C 46)
+# AMD64-NEXT:     Class: 64-bit (0x2)
+# AMD64-NEXT:     DataEncoding: LittleEndian (0x1)
+# AMD64-NEXT:     FileVersion: 1
+# AMD64-NEXT:     OS/ABI: FreeBSD (0x9)
+# AMD64-NEXT:     ABIVersion: 0
+# AMD64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# AMD64-NEXT:   }
+# AMD64-NEXT:   Type: Executable (0x2)
+# AMD64-NEXT:   Machine: EM_X86_64 (0x3E)
+# AMD64-NEXT:   Version: 1
+# AMD64-NEXT:   Entry:
+# AMD64-NEXT:   ProgramHeaderOffset: 0x40
+# AMD64-NEXT:   SectionHeaderOffset:
+# AMD64-NEXT:   Flags [ (0x0)
+# AMD64-NEXT:   ]
+# AMD64-NEXT:   HeaderSize: 64
+# AMD64-NEXT:   ProgramHeaderEntrySize: 56
+# AMD64-NEXT:   ProgramHeaderCount:
+# AMD64-NEXT:   SectionHeaderEntrySize: 64
+# AMD64-NEXT:   SectionHeaderCount:
+# AMD64-NEXT:   StringTableSectionIndex:
+# AMD64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx64
+# RUN: ld.lld -m elf_x86_64 %tx64 -o %t2x64
+# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s
+# RUN: ld.lld %tx64 -o %t3x64
+# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s
+# X86-64:      ElfHeader {
+# X86-64-NEXT:   Ident {
+# X86-64-NEXT:     Magic: (7F 45 4C 46)
+# X86-64-NEXT:     Class: 64-bit (0x2)
+# X86-64-NEXT:     DataEncoding: LittleEndian (0x1)
+# X86-64-NEXT:     FileVersion: 1
+# X86-64-NEXT:     OS/ABI: SystemV (0x0)
+# X86-64-NEXT:     ABIVersion: 0
+# X86-64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X86-64-NEXT:   }
+# X86-64-NEXT:   Type: Executable (0x2)
+# X86-64-NEXT:   Machine: EM_X86_64 (0x3E)
+# X86-64-NEXT:   Version: 1
+# X86-64-NEXT:   Entry:
+# X86-64-NEXT:   ProgramHeaderOffset: 0x40
+# X86-64-NEXT:   SectionHeaderOffset:
+# X86-64-NEXT:   Flags [ (0x0)
+# X86-64-NEXT:   ]
+# X86-64-NEXT:   HeaderSize: 64
+# X86-64-NEXT:   ProgramHeaderEntrySize: 56
+# X86-64-NEXT:   ProgramHeaderCount:
+# X86-64-NEXT:   SectionHeaderEntrySize: 64
+# X86-64-NEXT:   SectionHeaderCount:
+# X86-64-NEXT:   StringTableSectionIndex:
+# X86-64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnux32 %s -o %tx32
+# RUN: ld.lld -m elf32_x86_64 %tx32 -o %t2x32
+# RUN: llvm-readobj -file-headers %t2x32 | FileCheck --check-prefix=X32 %s
+# RUN: ld.lld %tx32 -o %t3x32
+# RUN: llvm-readobj -file-headers %t3x32 | FileCheck --check-prefix=X32 %s
+# X32:      ElfHeader {
+# X32-NEXT:   Ident {
+# X32-NEXT:     Magic: (7F 45 4C 46)
+# X32-NEXT:     Class: 32-bit (0x1)
+# X32-NEXT:     DataEncoding: LittleEndian (0x1)
+# X32-NEXT:     FileVersion: 1
+# X32-NEXT:     OS/ABI: SystemV (0x0)
+# X32-NEXT:     ABIVersion: 0
+# X32-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X32-NEXT:   }
+# X32-NEXT:   Type: Executable (0x2)
+# X32-NEXT:   Machine: EM_X86_64 (0x3E)
+# X32-NEXT:   Version: 1
+# X32-NEXT:   Entry:
+# X32-NEXT:   ProgramHeaderOffset: 0x34
+# X32-NEXT:   SectionHeaderOffset:
+# X32-NEXT:   Flags [ (0x0)
+# X32-NEXT:   ]
+# X32-NEXT:   HeaderSize: 52
+# X32-NEXT:   ProgramHeaderEntrySize: 32
+# X32-NEXT:   ProgramHeaderCount:
+# X32-NEXT:   SectionHeaderEntrySize: 40
+# X32-NEXT:   SectionHeaderCount:
+# X32-NEXT:   StringTableSectionIndex:
+# X32-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tx86
+# RUN: ld.lld -m elf_i386 %tx86 -o %t2x86
+# RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s
+# RUN: ld.lld %tx86 -o %t3x86
+# RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s
+# X86:      ElfHeader {
+# X86-NEXT:   Ident {
+# X86-NEXT:     Magic: (7F 45 4C 46)
+# X86-NEXT:     Class: 32-bit (0x1)
+# X86-NEXT:     DataEncoding: LittleEndian (0x1)
+# X86-NEXT:     FileVersion: 1
+# X86-NEXT:     OS/ABI: SystemV (0x0)
+# X86-NEXT:     ABIVersion: 0
+# X86-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X86-NEXT:   }
+# X86-NEXT:   Type: Executable (0x2)
+# X86-NEXT:   Machine: EM_386 (0x3)
+# X86-NEXT:   Version: 1
+# X86-NEXT:   Entry:
+# X86-NEXT:   ProgramHeaderOffset: 0x34
+# X86-NEXT:   SectionHeaderOffset:
+# X86-NEXT:   Flags [ (0x0)
+# X86-NEXT:   ]
+# X86-NEXT:   HeaderSize: 52
+# X86-NEXT:   ProgramHeaderEntrySize: 32
+# X86-NEXT:   ProgramHeaderCount:
+# X86-NEXT:   SectionHeaderEntrySize: 40
+# X86-NEXT:   SectionHeaderCount:
+# X86-NEXT:   StringTableSectionIndex:
+# X86-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-freebsd %s -o %tx86fbsd
+# RUN: ld.lld -m elf_i386_fbsd %tx86fbsd -o %t2x86_fbsd
+# RUN: llvm-readobj -file-headers %t2x86_fbsd | FileCheck --check-prefix=X86FBSD %s
+# RUN: ld.lld %tx86fbsd -o %t3x86fbsd
+# RUN: llvm-readobj -file-headers %t3x86fbsd | FileCheck --check-prefix=X86FBSD %s
+# X86FBSD:      ElfHeader {
+# X86FBSD-NEXT:   Ident {
+# X86FBSD-NEXT:     Magic: (7F 45 4C 46)
+# X86FBSD-NEXT:     Class: 32-bit (0x1)
+# X86FBSD-NEXT:     DataEncoding: LittleEndian (0x1)
+# X86FBSD-NEXT:     FileVersion: 1
+# X86FBSD-NEXT:     OS/ABI: FreeBSD (0x9)
+# X86FBSD-NEXT:     ABIVersion: 0
+# X86FBSD-NEXT:     Unused: (00 00 00 00 00 00 00)
+# X86FBSD-NEXT:   }
+# X86FBSD-NEXT:   Type: Executable (0x2)
+# X86FBSD-NEXT:   Machine: EM_386 (0x3)
+# X86FBSD-NEXT:   Version: 1
+# X86FBSD-NEXT:   Entry:
+# X86FBSD-NEXT:   ProgramHeaderOffset: 0x34
+# X86FBSD-NEXT:   SectionHeaderOffset:
+# X86FBSD-NEXT:   Flags [ (0x0)
+# X86FBSD-NEXT:   ]
+# X86FBSD-NEXT:   HeaderSize: 52
+# X86FBSD-NEXT:   ProgramHeaderEntrySize: 32
+# X86FBSD-NEXT:   ProgramHeaderCount:
+# X86FBSD-NEXT:   SectionHeaderEntrySize: 40
+# X86FBSD-NEXT:   SectionHeaderCount:
+# X86FBSD-NEXT:   StringTableSectionIndex:
+# X86FBSD-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i586-intel-elfiamcu %s -o %tiamcu
+# RUN: ld.lld -m elf_iamcu %tiamcu -o %t2iamcu
+# RUN: llvm-readobj -file-headers %t2iamcu | FileCheck --check-prefix=IAMCU %s
+# RUN: ld.lld %tiamcu -o %t3iamcu
+# RUN: llvm-readobj -file-headers %t3iamcu | FileCheck --check-prefix=IAMCU %s
+# IAMCU:      ElfHeader {
+# IAMCU-NEXT:   Ident {
+# IAMCU-NEXT:     Magic: (7F 45 4C 46)
+# IAMCU-NEXT:     Class: 32-bit (0x1)
+# IAMCU-NEXT:     DataEncoding: LittleEndian (0x1)
+# IAMCU-NEXT:     FileVersion: 1
+# IAMCU-NEXT:     OS/ABI: SystemV (0x0)
+# IAMCU-NEXT:     ABIVersion: 0
+# IAMCU-NEXT:     Unused: (00 00 00 00 00 00 00)
+# IAMCU-NEXT:   }
+# IAMCU-NEXT:   Type: Executable (0x2)
+# IAMCU-NEXT:   Machine: EM_IAMCU (0x6)
+# IAMCU-NEXT:   Version: 1
+# IAMCU-NEXT:   Entry:
+# IAMCU-NEXT:   ProgramHeaderOffset: 0x34
+# IAMCU-NEXT:   SectionHeaderOffset:
+# IAMCU-NEXT:   Flags [ (0x0)
+# IAMCU-NEXT:   ]
+# IAMCU-NEXT:   HeaderSize: 52
+# IAMCU-NEXT:   ProgramHeaderEntrySize: 32
+# IAMCU-NEXT:   ProgramHeaderCount:
+# IAMCU-NEXT:   SectionHeaderEntrySize: 40
+# IAMCU-NEXT:   SectionHeaderCount:
+# IAMCU-NEXT:   StringTableSectionIndex:
+# IAMCU-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %tppc64
+# RUN: ld.lld -m elf64ppc %tppc64 -o %t2ppc64
+# RUN: llvm-readobj -file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s
+# RUN: ld.lld %tppc64 -o %t3ppc64
+# RUN: llvm-readobj -file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s
+# PPC64:      ElfHeader {
+# PPC64-NEXT:   Ident {
+# PPC64-NEXT:     Magic: (7F 45 4C 46)
+# PPC64-NEXT:     Class: 64-bit (0x2)
+# PPC64-NEXT:     DataEncoding: BigEndian (0x2)
+# PPC64-NEXT:     FileVersion: 1
+# PPC64-NEXT:     OS/ABI: SystemV (0x0)
+# PPC64-NEXT:     ABIVersion: 0
+# PPC64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# PPC64-NEXT:   }
+# PPC64-NEXT:   Type: Executable (0x2)
+# PPC64-NEXT:   Machine: EM_PPC64 (0x15)
+# PPC64-NEXT:   Version: 1
+# PPC64-NEXT:   Entry:
+# PPC64-NEXT:   ProgramHeaderOffset: 0x40
+# PPC64-NEXT:   SectionHeaderOffset:
+# PPC64-NEXT:   Flags [ (0x0)
+# PPC64-NEXT:   ]
+# PPC64-NEXT:   HeaderSize: 64
+# PPC64-NEXT:   ProgramHeaderEntrySize: 56
+# PPC64-NEXT:   ProgramHeaderCount:
+# PPC64-NEXT:   SectionHeaderEntrySize: 64
+# PPC64-NEXT:   SectionHeaderCount:
+# PPC64-NEXT:   StringTableSectionIndex:
+# PPC64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %tmips
+# RUN: ld.lld -m elf32btsmip -e _start %tmips -o %t2mips
+# RUN: llvm-readobj -file-headers %t2mips | FileCheck --check-prefix=MIPS %s
+# RUN: ld.lld %tmips -e _start -o %t3mips
+# RUN: llvm-readobj -file-headers %t3mips | FileCheck --check-prefix=MIPS %s
+# MIPS:      ElfHeader {
+# MIPS-NEXT:   Ident {
+# MIPS-NEXT:     Magic: (7F 45 4C 46)
+# MIPS-NEXT:     Class: 32-bit (0x1)
+# MIPS-NEXT:     DataEncoding: BigEndian (0x2)
+# MIPS-NEXT:     FileVersion: 1
+# MIPS-NEXT:     OS/ABI: SystemV (0x0)
+# MIPS-NEXT:     ABIVersion: 0
+# MIPS-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPS-NEXT:   }
+# MIPS-NEXT:   Type: Executable (0x2)
+# MIPS-NEXT:   Machine: EM_MIPS (0x8)
+# MIPS-NEXT:   Version: 1
+# MIPS-NEXT:   Entry:
+# MIPS-NEXT:   ProgramHeaderOffset: 0x34
+# MIPS-NEXT:   SectionHeaderOffset:
+# MIPS-NEXT:   Flags [
+# MIPS-NEXT:     EF_MIPS_ABI_O32
+# MIPS-NEXT:     EF_MIPS_ARCH_32
+# MIPS-NEXT:     EF_MIPS_CPIC
+# MIPS-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %tmipsel
+# RUN: ld.lld -m elf32ltsmip -e _start %tmipsel -o %t2mipsel
+# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
+# RUN: ld.lld -melf32ltsmip -e _start %tmipsel -o %t2mipsel
+# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
+# RUN: ld.lld %tmipsel -e _start -o %t3mipsel
+# RUN: llvm-readobj -file-headers %t3mipsel | FileCheck --check-prefix=MIPSEL %s
+# MIPSEL:      ElfHeader {
+# MIPSEL-NEXT:   Ident {
+# MIPSEL-NEXT:     Magic: (7F 45 4C 46)
+# MIPSEL-NEXT:     Class: 32-bit (0x1)
+# MIPSEL-NEXT:     DataEncoding: LittleEndian (0x1)
+# MIPSEL-NEXT:     FileVersion: 1
+# MIPSEL-NEXT:     OS/ABI: SystemV (0x0)
+# MIPSEL-NEXT:     ABIVersion: 0
+# MIPSEL-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPSEL-NEXT:   }
+# MIPSEL-NEXT:   Type: Executable (0x2)
+# MIPSEL-NEXT:   Machine: EM_MIPS (0x8)
+# MIPSEL-NEXT:   Version: 1
+# MIPSEL-NEXT:   Entry:
+# MIPSEL-NEXT:   ProgramHeaderOffset: 0x34
+# MIPSEL-NEXT:   SectionHeaderOffset:
+# MIPSEL-NEXT:   Flags [
+# MIPSEL-NEXT:     EF_MIPS_ABI_O32
+# MIPSEL-NEXT:     EF_MIPS_ARCH_32
+# MIPSEL-NEXT:     EF_MIPS_CPIC
+# MIPSEL-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -position-independent \
+# RUN:         %s -o %tmips64
+# RUN: ld.lld -m elf64btsmip -e _start %tmips64 -o %t2mips64
+# RUN: llvm-readobj -file-headers %t2mips64 | FileCheck --check-prefix=MIPS64 %s
+# RUN: ld.lld %tmips64 -e _start -o %t3mips64
+# RUN: llvm-readobj -file-headers %t3mips64 | FileCheck --check-prefix=MIPS64 %s
+# MIPS64:      ElfHeader {
+# MIPS64-NEXT:   Ident {
+# MIPS64-NEXT:     Magic: (7F 45 4C 46)
+# MIPS64-NEXT:     Class: 64-bit (0x2)
+# MIPS64-NEXT:     DataEncoding: BigEndian (0x2)
+# MIPS64-NEXT:     FileVersion: 1
+# MIPS64-NEXT:     OS/ABI: SystemV (0x0)
+# MIPS64-NEXT:     ABIVersion: 0
+# MIPS64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPS64-NEXT:   }
+# MIPS64-NEXT:   Type: Executable (0x2)
+# MIPS64-NEXT:   Machine: EM_MIPS (0x8)
+# MIPS64-NEXT:   Version: 1
+# MIPS64-NEXT:   Entry:
+# MIPS64-NEXT:   ProgramHeaderOffset: 0x40
+# MIPS64-NEXT:   SectionHeaderOffset:
+# MIPS64-NEXT:   Flags [
+# MIPS64-NEXT:     EF_MIPS_ARCH_64
+# MIPS64-NEXT:     EF_MIPS_CPIC
+# MIPS64-NEXT:     EF_MIPS_PIC
+# MIPS64-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux \
+# RUN:         -position-independent %s -o %tmips64el
+# RUN: ld.lld -m elf64ltsmip -e _start %tmips64el -o %t2mips64el
+# RUN: llvm-readobj -file-headers %t2mips64el | FileCheck --check-prefix=MIPS64EL %s
+# RUN: ld.lld %tmips64el -e _start -o %t3mips64el
+# RUN: llvm-readobj -file-headers %t3mips64el | FileCheck --check-prefix=MIPS64EL %s
+# MIPS64EL:      ElfHeader {
+# MIPS64EL-NEXT:   Ident {
+# MIPS64EL-NEXT:     Magic: (7F 45 4C 46)
+# MIPS64EL-NEXT:     Class: 64-bit (0x2)
+# MIPS64EL-NEXT:     DataEncoding: LittleEndian (0x1)
+# MIPS64EL-NEXT:     FileVersion: 1
+# MIPS64EL-NEXT:     OS/ABI: SystemV (0x0)
+# MIPS64EL-NEXT:     ABIVersion: 0
+# MIPS64EL-NEXT:     Unused: (00 00 00 00 00 00 00)
+# MIPS64EL-NEXT:   }
+# MIPS64EL-NEXT:   Type: Executable (0x2)
+# MIPS64EL-NEXT:   Machine: EM_MIPS (0x8)
+# MIPS64EL-NEXT:   Version: 1
+# MIPS64EL-NEXT:   Entry:
+# MIPS64EL-NEXT:   ProgramHeaderOffset: 0x40
+# MIPS64EL-NEXT:   SectionHeaderOffset:
+# MIPS64EL-NEXT:   Flags [
+# MIPS64EL-NEXT:     EF_MIPS_ARCH_64
+# MIPS64EL-NEXT:     EF_MIPS_CPIC
+# MIPS64EL-NEXT:     EF_MIPS_PIC
+# MIPS64EL-NEXT:   ]
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %taarch64
+# RUN: ld.lld -m aarch64linux %taarch64 -o %t2aarch64
+# RUN: llvm-readobj -file-headers %t2aarch64 | FileCheck --check-prefix=AARCH64 %s
+# RUN: ld.lld %taarch64 -o %t3aarch64
+# RUN: llvm-readobj -file-headers %t3aarch64 | FileCheck --check-prefix=AARCH64 %s
+# AARCH64:      ElfHeader {
+# AARCH64-NEXT:   Ident {
+# AARCH64-NEXT:     Magic: (7F 45 4C 46)
+# AARCH64-NEXT:     Class: 64-bit (0x2)
+# AARCH64-NEXT:     DataEncoding: LittleEndian (0x1)
+# AARCH64-NEXT:     FileVersion: 1
+# AARCH64-NEXT:     OS/ABI: SystemV (0x0)
+# AARCH64-NEXT:     ABIVersion: 0
+# AARCH64-NEXT:     Unused: (00 00 00 00 00 00 00)
+# AARCH64-NEXT:   }
+# AARCH64-NEXT:   Type: Executable (0x2)
+# AARCH64-NEXT:   Machine: EM_AARCH64 (0xB7)
+# AARCH64-NEXT:   Version: 1
+# AARCH64-NEXT:   Entry:
+# AARCH64-NEXT:   ProgramHeaderOffset: 0x40
+# AARCH64-NEXT:   SectionHeaderOffset:
+# AARCH64-NEXT:   Flags [ (0x0)
+# AARCH64-NEXT:   ]
+
+# REQUIRES: x86,ppc,mips,aarch64
+
+.globl _start
+_start:
diff --git a/test/ELF/end-abs.s b/test/ELF/end-abs.s
new file mode 100644 (file)
index 0000000..2199ce2
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+.long _end - .
diff --git a/test/ELF/end-preserve.s b/test/ELF/end-preserve.s
new file mode 100644 (file)
index 0000000..71d86d1
--- /dev/null
@@ -0,0 +1,16 @@
+// Should preserve the value of the "end" symbol if it is defined.
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-nm %t | FileCheck %s
+
+// CHECK: 0000000000000005 A end
+
+.global _start,end
+end = 5
+.text
+_start:
+    nop
+.bss
+    .space 6
diff --git a/test/ELF/end-update.s b/test/ELF/end-update.s
new file mode 100644 (file)
index 0000000..afb137f
--- /dev/null
@@ -0,0 +1,29 @@
+// Should set the value of the "end" symbol if it is undefined.
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -sections -symbols %t | FileCheck %s
+
+// CHECK: Sections [
+// CHECK:     Name: .bss
+// CHECK-NEXT:     Type:
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x202000
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 6
+// CHECK: ]
+// CHECK: Symbols [
+// CHECK:     Name: end
+// CHECK-NEXT:     Value: 0x202006
+// CHECK: ]
+
+.global _start,end
+.text
+_start:
+    nop
+.bss
+    .space 6
diff --git a/test/ELF/end.s b/test/ELF/end.s
new file mode 100644 (file)
index 0000000..f40c5db
--- /dev/null
@@ -0,0 +1,37 @@
+// Should set the value of the "_end" symbol to the end of the data segment.
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+// By default, the .bss section is the latest section of the data segment.
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=DEFAULT
+
+// DEFAULT: Sections [
+// DEFAULT:     Name: .bss
+// DEFAULT-NEXT:     Type:
+// DEFAULT-NEXT:     Flags [
+// DEFAULT-NEXT:       SHF_ALLOC
+// DEFAULT-NEXT:       SHF_WRITE
+// DEFAULT-NEXT:     ]
+// DEFAULT-NEXT:     Address: 0x202002
+// DEFAULT-NEXT:     Offset:
+// DEFAULT-NEXT:     Size: 6
+// DEFAULT: ]
+// DEFAULT: Symbols [
+// DEFAULT:     Name: _end
+// DEFAULT-NEXT:     Value: 0x202008
+// DEFAULT: ]
+
+// RUN: ld.lld -r %t.o -o %t2
+// RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=RELOCATABLE
+// RELOCATABLE: 0000000000000000 *UND* 00000000 _end
+
+.global _start,_end
+.text
+_start:
+    nop
+.data
+    .word 1
+.bss
+    .space 6
diff --git a/test/ELF/entry.s b/test/ELF/entry.s
new file mode 100644 (file)
index 0000000..f288bcf
--- /dev/null
@@ -0,0 +1,53 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+
+# RUN: ld.lld -e foobar %t1 -o %t2 2>&1 | FileCheck -check-prefix=WARN1 %s
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=TEXT %s
+
+# WARN1: warning: cannot find entry symbol foobar; defaulting to 0x201000
+# TEXT: Entry: 0x201000
+
+# RUN: ld.lld %t1 -o %t2 2>&1 | FileCheck -check-prefix=WARN2 %s
+# WARN2: warning: cannot find entry symbol _start; defaulting to 0x201000
+
+# RUN: ld.lld -shared -e foobar %t1 -o %t2 2>&1 | FileCheck -check-prefix=WARN3 %s
+# WARN3: warning: cannot find entry symbol foobar; defaulting to 0x1000
+
+# RUN: ld.lld -shared --fatal-warnings -e entry %t1 -o %t2
+# RUN: ld.lld -shared --fatal-warnings %t1 -o %t2
+
+# RUN: echo .data > %t.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -n %t.s -o %t3
+# RUN: ld.lld %t3 -o %t4 2>&1 | FileCheck -check-prefix=WARN4 %s
+# RUN: llvm-readobj -file-headers %t4 | FileCheck -check-prefix=NOENTRY %s
+
+# WARN4: cannot find entry symbol _start; not setting start address
+# NOENTRY: Entry: 0x0
+
+# RUN: ld.lld -v -r %t1 -o %t2 2>&1 | FileCheck -check-prefix=WARN5 %s
+# WARN5-NOT: warning: cannot find entry symbol
+
+# RUN: ld.lld %t1 -o %t2 -e entry
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=SYM %s
+# SYM: Entry: 0x201008
+
+# RUN: ld.lld %t1 --fatal-warnings -shared -o %t2 -e entry
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=DSO %s
+# DSO: Entry: 0x1008
+
+# RUN: ld.lld %t1 -o %t2 --entry=4096
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=DEC %s
+# DEC: Entry: 0x1000
+
+# RUN: ld.lld %t1 -o %t2 --entry 0xcafe
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=HEX %s
+# HEX: Entry: 0xCAFE
+
+# RUN: ld.lld %t1 -o %t2 -e 0777
+# RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=OCT %s
+# OCT: Entry: 0x1FF
+
+.globl entry
+.text
+       .quad 0
+entry:
+       ret
diff --git a/test/ELF/error-limit.test b/test/ELF/error-limit.test
new file mode 100644 (file)
index 0000000..a82f2f2
--- /dev/null
@@ -0,0 +1,26 @@
+RUN: not ld.lld 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 \
+RUN:   21 22 2>&1 | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT:      cannot open 01
+DEFAULT:      cannot open 20
+DEFAULT-NEXT: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
+DEFAULT-NOT:  cannot open 21
+
+RUN: not ld.lld -error-limit=5 01 02 03 04 05 06 07 08 09 10 2>&1 \
+RUN:   | FileCheck -check-prefix=LIMIT5 %s
+RUN: not ld.lld -error-limit 5 01 02 03 04 05 06 07 08 09 10 2>&1 \
+RUN:   | FileCheck -check-prefix=LIMIT5 %s
+
+LIMIT5:      cannot open 01
+LIMIT5:      cannot open 05
+LIMIT5-NEXT: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
+LIMIT5-NOT:  cannot open 06
+
+RUN: not ld.lld -error-limit=0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
+RUN:   16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=UNLIMITED %s
+
+UNLIMITED:     cannot open 01
+UNLIMITED:     cannot open 20
+UNLIMITED:     cannot open 21
+UNLIMITED:     cannot open 22
+UNLIMITED-NOT: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
diff --git a/test/ELF/exclude-libs.s b/test/ELF/exclude-libs.s
new file mode 100644 (file)
index 0000000..c36081f
--- /dev/null
@@ -0,0 +1,30 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/exclude-libs.s -o %t2.o
+// RUN: mkdir -p %t.dir
+// RUN: rm -f %t.dir/exc.a
+// RUN: llvm-ar rcs %t.dir/exc.a %t2.o
+
+// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe
+// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s
+
+// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=foo,bar
+// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s
+
+// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo,bar,exc.a
+// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s
+
+// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo:bar:exc.a
+// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s
+
+// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL
+// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s
+
+// DEFAULT: Name: fn
+// EXCLUDE-NOT: Name: fn
+
+.globl fn
+foo:
+  call fn@PLT
diff --git a/test/ELF/exclude.s b/test/ELF/exclude.s
new file mode 100644 (file)
index 0000000..8fe0037
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -o %t1 %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# RUN: ld.lld -r -o %t1 %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck --check-prefix=RELOCATABLE %s
+
+# CHECK-NOT:      .aaa
+# RELOCATABLE:    .aaa
+
+.globl _start
+_start:
+  jmp _start
+
+.section .aaa,"ae"
+ .quad .bbb
+
+.section .bbb,"a"
+ .quad 0
diff --git a/test/ELF/fatal-warnings.s b/test/ELF/fatal-warnings.s
new file mode 100644 (file)
index 0000000..0bc2a2b
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/warn-common.s -o %t2.o
+
+# RUN: ld.lld --warn-common %t1.o %t2.o -o %t1.out 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR %s
+# ERR: multiple common of
+
+# RUN: not ld.lld --warn-common --fatal-warnings %t1.o %t2.o -o %t2.out 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR %s
+
+.globl _start
+_start:
+
+.type arr,@object
+.comm arr,4,4
diff --git a/test/ELF/file-sym.s b/test/ELF/file-sym.s
new file mode 100644 (file)
index 0000000..eddb461
--- /dev/null
@@ -0,0 +1,12 @@
+# Check that we do not keep STT_FILE symbols in the symbol table
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -symbols %t.so | FileCheck %s
+
+# REQUIRES: x86
+
+# CHECK-NOT: xxx
+
+.file "xxx"
+.file ""
diff --git a/test/ELF/filter.s b/test/ELF/filter.s
new file mode 100644 (file)
index 0000000..fa8e526
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -F foo.so -F boo.so -o %t1
+# RUN: llvm-readobj --dynamic-table %t1 | FileCheck %s
+
+# Test alias.
+# RUN: ld.lld %t.o -shared --filter=foo.so --filter=boo.so -o %t2
+# RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s
+
+# CHECK:      DynamicSection [
+# CHECK-NEXT: Tag                Type          Name/Value
+# CHECK-NEXT: 0x000000007FFFFFFF FILTER        Filter library: [foo.so]
+# CHECK-NEXT: 0x000000007FFFFFFF FILTER        Filter library: [boo.so]
+
+# RUN: not ld.lld %t.o -F x -o %t 2>&1 | FileCheck -check-prefix=ERR %s
+# ERR: -F may not be used without -shared
diff --git a/test/ELF/format-binary.test b/test/ELF/format-binary.test
new file mode 100644 (file)
index 0000000..94b9b51
--- /dev/null
@@ -0,0 +1,57 @@
+# REQUIRES: x86
+
+# RUN: echo -n "Fluffle Puff" > %t.binary
+# RUN: ld.lld -m elf_x86_64 -r -b binary %t.binary -o %t.out
+# RUN: llvm-readobj %t.out -sections -section-data -symbols | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -b binary %t.binary -b default %t.o -shared -o %t.out
+
+# RUN: not ld.lld -b foo > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ERR %s < %t.log
+# ERR: error: unknown -format value: foo (supported formats: elf, default, binary)
+
+# CHECK:          Name: .data
+# CHECK-NEXT:     Type: SHT_PROGBITS
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       SHF_ALLOC
+# CHECK-NEXT:       SHF_WRITE
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x0
+# CHECK-NEXT:     Offset:
+# CHECK-NEXT:     Size: 12
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment:
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:       0000: 466C7566 666C6520 50756666           |Fluffle Puff|
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+
+# CHECK:          Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_test_tmp_binary_start
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .data
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_test_tmp_binary_end
+# CHECK-NEXT:     Value: 0xC
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .data
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_test_tmp_binary_size
+# CHECK-NEXT:     Value: 0xC
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Absolute
+# CHECK-NEXT:   }
diff --git a/test/ELF/gc-absolute.s b/test/ELF/gc-absolute.s
new file mode 100644 (file)
index 0000000..29e6716
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 -shared --gc-sections
+
+.global foo
+foo = 0x123
diff --git a/test/ELF/gc-debuginfo-tls.s b/test/ELF/gc-debuginfo-tls.s
new file mode 100644 (file)
index 0000000..d1a250b
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o --gc-sections -shared -o %t1
+# RUN: ld.lld %t.o -shared -o %t2
+# RUN: llvm-readobj -symbols %t1 | FileCheck %s --check-prefix=GC
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=NOGC
+
+# NOGC:      Symbol {
+# NOGC:        Name: patatino
+# NOGC-NEXT:   Value: 0x0
+# NOGC-NEXT:   Size: 0
+# NOGC-NEXT:   Binding: Local
+# NOGC-NEXT:   Type: TLS
+# NOGC-NEXT:   Other: 0
+# NOGC-NEXT:   Section: .tbss
+# NOGC-NEXT: }
+
+# GC-NOT: tbss
+
+.section .tbss,"awT",@nobits
+patatino:
+  .long 0
+  .section .noalloc,""
+  .quad patatino
diff --git a/test/ELF/gc-merge-local-sym.s b/test/ELF/gc-merge-local-sym.s
new file mode 100644 (file)
index 0000000..a4540af
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared -O3 --gc-sections
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 61626300 |abc.|
+// CHECK-NEXT: )
+
+// CHECK:      Symbols [
+// CHECK:        Symbol {
+// CHECK-NOT:          Name: bar
+
+        .global foo
+foo:
+        leaq    .L.str(%rip), %rsi
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "abc"
+bar:
+        .asciz  "def"
diff --git a/test/ELF/gc-sections-alloc.s b/test/ELF/gc-sections-alloc.s
new file mode 100644 (file)
index 0000000..bffd1f9
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --gc-sections -shared
+# RUN: llvm-readobj -sections  -section-data %t2 | FileCheck %s
+
+# Non alloca section .bar should not keep section .foo alive.
+
+# CHECK-NOT: Name: .foo
+
+# CHECK:      Name: .bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT:   0000: 00000000 00000000                    |
+# CHECK-NEXT: )
+
+
+.section .foo,"a"
+.byte 0
+
+.section .bar
+.quad .foo
diff --git a/test/ELF/gc-sections-eh.s b/test/ELF/gc-sections-eh.s
new file mode 100644 (file)
index 0000000..88c3dd0
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld %t -o %t2 --gc-sections
+# RUN: llvm-readobj -t %t2 | FileCheck %s
+# RUN: llvm-objdump --dwarf=frames %t2 | FileCheck --check-prefix=EH %s
+
+# RUN: ld.lld %t -o %t3
+# RUN: llvm-readobj -t %t3 | FileCheck --check-prefix=NOGC %s
+# RUN: llvm-objdump --dwarf=frames %t3 | FileCheck --check-prefix=EHNOGC %s
+
+# CHECK-NOT: foo
+# NOGC:      foo
+
+# EH:     FDE cie={{.*}} pc=
+# EH-NOT: FDE
+
+# EHNOGC: FDE cie={{.*}} pc=
+# EHNOGC: FDE cie={{.*}} pc=
+
+       .section        .text,"ax",@progbits,unique,0
+       .globl  foo
+foo:
+       .cfi_startproc
+       .cfi_endproc
+
+       .section        .text,"ax",@progbits,unique,1
+       .globl  _start
+_start:
+       .cfi_startproc
+       .cfi_endproc
diff --git a/test/ELF/gc-sections-implicit-addend.s b/test/ELF/gc-sections-implicit-addend.s
new file mode 100644 (file)
index 0000000..1270aff
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t --gc-sections
+# RUN: llvm-readobj -s %t | FileCheck %s
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+# CHECK:      Name: .foo
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_ALLOC
+# CHECK-NEXT:   SHF_MERGE
+# CHECK-NEXT:   SHF_STRINGS
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x100B4
+
+# 0x100B4 == 65716
+# DISASM: leal    65716, %eax
+
+        .section        .foo,"aMS",@progbits,1
+        .byte 0
+
+        .text
+        .global _start
+_start:
+        leal    .foo, %eax
diff --git a/test/ELF/gc-sections-keep-shared-start.s b/test/ELF/gc-sections-keep-shared-start.s
new file mode 100644 (file)
index 0000000..23417ca
--- /dev/null
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -shared --gc-sections -o %t1 %t
+# RUN: llvm-readobj --elf-output-style=GNU --file-headers --symbols %t1
+#   | FileCheck %s
+# CHECK: Entry point address:               0x1000
+# CHECK: 0000000000001000     0 FUNC    LOCAL  HIDDEN     4 _start
+# CHECK: 0000000000001006     0 FUNC    LOCAL  HIDDEN     4 internal
+# CHECK: 0000000000001005     0 FUNC    GLOBAL DEFAULT    4 foobar
+
+.section .text.start,"ax"
+.globl _start
+.type _start,%function
+.hidden _start
+_start:
+  jmp internal
+
+.section .text.foobar,"ax"
+.globl foobar
+.type foobar,%function
+foobar:
+  ret
+
+.section .text.internal,"ax"
+.globl internal
+.hidden internal
+.type internal,%function
+internal:
+       ret
diff --git a/test/ELF/gc-sections-local-sym.s b/test/ELF/gc-sections-local-sym.s
new file mode 100644 (file)
index 0000000..89121e2
--- /dev/null
@@ -0,0 +1,57 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2 -shared --gc-sections
+// RUN: llvm-readobj -t -s -section-data %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global foo
+foo:
+
+.section .bar,"a"
+zed:
+
+// CHECK:      Name: .strtab
+// CHECK-NEXT: Type: SHT_STRTAB
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00666F6F 005F4459 4E414D49 4300      |.foo._DYNAMIC.|
+// CHECK-NEXT: )
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x1000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/gc-sections-lsda.s b/test/ELF/gc-sections-lsda.s
new file mode 100644 (file)
index 0000000..1fc75c8
--- /dev/null
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld -shared --gc-sections %t.o -o %t
+
+// Test that we handle .eh_frame keeping sections alive. We could be more
+// precise and gc the entire contents of this file, but test that at least
+// we are consistent: if we keep .abc, we have to keep .foo
+
+// RUN: llvm-readobj -s %t | FileCheck %s
+// CHECK:  Name: .abc
+// CHECK: Name: .foo
+
+        .cfi_startproc
+        .cfi_lsda 0x1b,zed
+        .cfi_endproc
+        .section        .abc,"a"
+zed:
+        .long   bar-.
+        .section        .foo,"ax"
+bar:
diff --git a/test/ELF/gc-sections-merge-addend.s b/test/ELF/gc-sections-merge-addend.s
new file mode 100644 (file)
index 0000000..1c1f6ee
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 62617200                    |bar.|
+// CHECK-NEXT: )
+
+        .section        .data.f,"aw",@progbits
+        .globl  f
+f:
+        .quad .rodata.str1.1 + 4
+
+        .section        .data.g,"aw",@progbits
+        .hidden g
+        .globl  g
+g:
+        .quad .rodata.str1.1
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "foo"
+.L.str.1:
+        .asciz  "bar"
diff --git a/test/ELF/gc-sections-merge-implicit-addend.s b/test/ELF/gc-sections-merge-implicit-addend.s
new file mode 100644 (file)
index 0000000..c725e29
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 62617200                    |bar.|
+// CHECK-NEXT: )
+
+        .section        .data.f,"aw",@progbits
+        .globl  f
+f:
+        .long .rodata.str1.1 + 4
+
+        .section        .data.g,"aw",@progbits
+        .hidden g
+        .globl  g
+g:
+        .long .rodata.str1.1
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "foo"
+.L.str.1:
+        .asciz  "bar"
diff --git a/test/ELF/gc-sections-merge.s b/test/ELF/gc-sections-merge.s
new file mode 100644 (file)
index 0000000..d7b3eae
--- /dev/null
@@ -0,0 +1,61 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: ld.lld %t.o -o %t.gc.so -shared --gc-sections
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+// RUN: llvm-readobj -s -section-data %t.gc.so | FileCheck --check-prefix=GC %s
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 666F6F00 62617200                    |foo.bar.|
+// CHECK-NEXT: )
+
+// GC:      Name: .rodata
+// GC-NEXT: Type: SHT_PROGBITS
+// GC-NEXT: Flags [
+// GC-NEXT:   SHF_ALLOC
+// GC-NEXT:   SHF_MERGE
+// GC-NEXT:   SHF_STRINGS
+// GC-NEXT: ]
+// GC-NEXT: Address:
+// GC-NEXT: Offset:
+// GC-NEXT: Size: 4
+// GC-NEXT: Link: 0
+// GC-NEXT: Info: 0
+// GC-NEXT: AddressAlignment: 1
+// GC-NEXT: EntrySize: 0
+// GC-NEXT: SectionData (
+// GC-NEXT:   0000: 666F6F00                                |foo.|
+// GC-NEXT: )
+
+        .section        .text.f,"ax",@progbits
+        .globl  f
+f:
+        leaq    .L.str(%rip), %rax
+        retq
+
+        .section        .text.g,"ax",@progbits
+        .hidden g
+        .globl  g
+g:
+        leaq    .L.str.1(%rip), %rax
+        retq
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+        .asciz  "foo"
+.L.str.1:
+        .asciz  "bar"
diff --git a/test/ELF/gc-sections-metadata-startstop.s b/test/ELF/gc-sections-metadata-startstop.s
new file mode 100644 (file)
index 0000000..10c0b54
--- /dev/null
@@ -0,0 +1,33 @@
+# LINK_ORDER cnamed sections are not kept alive by the __start_* reference.
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --gc-sections %t.o -o %t
+# RUN: llvm-objdump -section-headers -t %t | FileCheck  %s
+
+# CHECK: Sections:
+# CHECK-NOT: yy
+# CHECK: xx {{.*}} DATA
+# CHECK-NOT: yy
+
+# CHECK: SYMBOL TABLE:
+# CHECK: xx 00000000 __start_xx
+# CHECK: w *UND* 00000000 __start_yy
+
+.weak __start_xx
+.weak __start_yy
+
+.global _start
+_start:
+.quad __start_xx
+.quad __start_yy
+
+.section xx,"a"
+.quad 0
+
+.section .foo,"a"
+.quad 0
+
+.section yy,"ao",@progbits,.foo
+.quad 0
+
diff --git a/test/ELF/gc-sections-metadata.s b/test/ELF/gc-sections-metadata.s
new file mode 100644 (file)
index 0000000..2e696f8
--- /dev/null
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --gc-sections %t.o -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck  %s
+
+# CHECK:      1 .foo1
+# CHECK-NEXT:   bar1
+# CHECK-NEXT:   .zed1
+# CHECK-NEXT:   .text
+# CHECK-NEXT:   .comment
+# CHECK-NEXT:   .symtab
+# CHECK-NEXT:   .shstrtab
+# CHECK-NEXT:   .strtab
+
+.global _start
+_start:
+.quad .foo1
+
+.section .foo1,"a"
+.quad 0
+
+.section .foo2,"a"
+.quad 0
+
+.section bar1,"ao",@progbits,.foo1
+.quad .zed1
+.quad .foo1
+
+.section bar2,"ao",@progbits,.foo2
+.quad .zed2
+.quad .foo2
+
+.section .zed1,"a"
+.quad 0
+
+.section .zed2,"a"
+.quad 0
diff --git a/test/ELF/gc-sections-metadata2.s b/test/ELF/gc-sections-metadata2.s
new file mode 100644 (file)
index 0000000..3a3b640
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --gc-sections %t.o -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+# CHECK: .foo
+# CHECK: .bar
+# CHECK: .zed
+
+.globl _start
+_start:
+.quad .foo
+
+.section .foo,"a"
+.quad 0
+.section .bar,"ao",@progbits,.foo
+.quad 0
+.section .zed,"ao",@progbits,.foo
+.quad 0
diff --git a/test/ELF/gc-sections-non-alloc-to-merge.s b/test/ELF/gc-sections-non-alloc-to-merge.s
new file mode 100644 (file)
index 0000000..37b0328
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t --gc-sections
+# RUN: llvm-readobj -s --elf-output-style=GNU %t | FileCheck %s
+
+# CHECK:  .merge1     PROGBITS    {{[0-9a-z]*}} {{[0-9a-z]*}} 000004
+
+        .global _start
+_start:
+        .quad .Lfoo
+
+        .section        .merge1,"aM",@progbits,4
+        .p2align        2
+.Lfoo:
+        .long 1
+.Lbar:
+        .long 2
+
+        .section        .merge2,"aM",@progbits,4
+        .p2align        2
+.Lzed:
+        .long 1
+
+        .section bar
+        .quad .Lbar
+       .quad .Lzed
diff --git a/test/ELF/gc-sections-print.s b/test/ELF/gc-sections-print.s
new file mode 100644 (file)
index 0000000..59177a6
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t --gc-sections --print-gc-sections -o %t2 2>&1 | FileCheck -check-prefix=PRINT %s
+
+# PRINT:      removing unused section from '.text.x' in file
+# PRINT-NEXT: removing unused section from '.text.y' in file
+
+.globl _start
+.protected a, x, y
+_start:
+ call a
+
+.section .text.a,"ax",@progbits
+a:
+ nop
+
+.section .text.x,"ax",@progbits
+x:
+ nop
+
+.section .text.y,"ax",@progbits
+y:
+ nop
diff --git a/test/ELF/gc-sections-protected.s b/test/ELF/gc-sections-protected.s
new file mode 100644 (file)
index 0000000..9f1efed
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 1
+
+.protected g
+.globl g
+g:
+retq
diff --git a/test/ELF/gc-sections-shared.s b/test/ELF/gc-sections-shared.s
new file mode 100644 (file)
index 0000000..efb21fa
--- /dev/null
@@ -0,0 +1,59 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --gc-sections --export-dynamic-symbol foo -o %t %t.o --as-needed %t2.so
+# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck %s
+
+# This test the property that we have a needed line for every undefined.
+# It would also be OK to drop bar2 and the need for the .so
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: bar2
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK: NEEDED Shared library: [{{.*}}.so]
+
+.section .text.foo, "ax"
+.globl foo
+foo:
+call bar
+
+.section .text.bar, "ax"
+.globl bar
+bar:
+ret
+
+.section .text._start, "ax"
+.globl _start
+_start:
+ret
+
+.section .text.unused, "ax"
+call bar2
diff --git a/test/ELF/gc-sections-synthetic.s b/test/ELF/gc-sections-synthetic.s
new file mode 100644 (file)
index 0000000..e47cc02
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+
+# Linker-synthesized sections shouldn't be gc'ed.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t1
+# RUN: ld.lld %t1 -shared -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2
+# RUN: ld.lld %t2 %t.so -build-id -dynamic-linker /foo/bar -o %t.out
+# RUN: llvm-readobj -sections %t.out | FileCheck %s
+
+# CHECK: Name: .interp
+# CHECK: Name: .note.gnu.build-id
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/gc-sections-weak.s b/test/ELF/gc-sections-weak.s
new file mode 100644 (file)
index 0000000..625b613
--- /dev/null
@@ -0,0 +1,24 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/gc-sections-weak.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t.so -shared --gc-sections
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+.global foo
+foo:
+nop
+
+.data
+.global bar1
+bar1:
+.quad foo
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 1
diff --git a/test/ELF/gc-sections.s b/test/ELF/gc-sections.s
new file mode 100644 (file)
index 0000000..0ae6fa4
--- /dev/null
@@ -0,0 +1,108 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=NOGC %s
+# RUN: ld.lld --gc-sections %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC1 %s
+# RUN: ld.lld --export-dynamic --gc-sections %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC2 %s
+
+# NOGC: Name: .eh_frame
+# NOGC: Name: .text
+# NOGC: Name: .init
+# NOGC: Name: .fini
+# NOGC: Name: .ctors
+# NOGC: Name: .dtors
+# NOGC: Name: .debug_pubtypes
+# NOGC: Name: .comment
+# NOGC: Name: a
+# NOGC: Name: b
+# NOGC: Name: c
+# NOGC: Name: x
+# NOGC: Name: y
+# NOGC: Name: d
+
+# GC1:     Name: .eh_frame
+# GC1:     Name: .text
+# GC1:     Name: .init
+# GC1:     Name: .fini
+# GC1:     Name: .ctors
+# GC1:     Name: .dtors
+# GC1:     Name: .debug_pubtypes
+# GC1:     Name: .comment
+# GC1:     Name: a
+# GC1:     Name: b
+# GC1:     Name: c
+# GC1-NOT: Name: x
+# GC1-NOT: Name: y
+# GC1-NOT: Name: d
+
+# GC2:     Name: .eh_frame
+# GC2:     Name: .text
+# GC2:     Name: .init
+# GC2:     Name: .fini
+# GC2:     Name: .ctors
+# GC2:     Name: .dtors
+# GC2:     Name: .debug_pubtypes
+# GC2:     Name: .comment
+# GC2:     Name: a
+# GC2:     Name: b
+# GC2:     Name: c
+# GC2-NOT: Name: x
+# GC2-NOT: Name: y
+# GC2:     Name: d
+
+.globl _start, d
+.protected a, b, c, x, y
+_start:
+  call a
+
+.section .text.a,"ax",@progbits
+a:
+  call _start
+  call b
+
+.section .text.b,"ax",@progbits
+b:
+  call c
+
+.section .text.c,"ax",@progbits
+c:
+  nop
+
+.section .text.d,"ax",@progbits
+d:
+  nop
+
+.section .text.x,"ax",@progbits
+x:
+  call y
+
+.section .text.y,"ax",@progbits
+y:
+  call x
+
+.section .ctors,"aw",@progbits
+  .quad 0
+
+.section .dtors,"aw",@progbits
+  .quad 0
+
+.section .init,"aw",@init_array
+  .quad 0
+
+.section .fini,"aw",@fini_array
+  .quad 0
+
+.section .preinit_array,"aw",@preinit_array
+  .quad 0
+
+.section .eh_frame,"a",@unwind
+  .quad 0
+
+.section .debug_pubtypes,"",@progbits
+  .quad 0
+
+.section .comment,"MS",@progbits,8
+  .quad 0
diff --git a/test/ELF/gdb-index-dup-types.s b/test/ELF/gdb-index-dup-types.s
new file mode 100644 (file)
index 0000000..e0bed33
--- /dev/null
@@ -0,0 +1,60 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --gdb-index %t.o -o %t
+# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s
+
+## Testcase is based on output produced by gcc version 5.4.1 20160904
+## it has duplicate entries in .debug_gnu_pubtypes which seems to be
+## compiler bug. In that case it is useless to have them in .gdb_index
+## and we filter such entries out to reduce size of .gdb_index.
+
+## CHECK: Constant pool offset = {{.*}}, has 1 CU vectors:
+## CHECK-NOT: 0(0x0): 0x90000000 0x90000000
+
+.section .debug_abbrev,"",@progbits
+ .byte 1                       # Abbreviation Code
+ .byte 17                      # DW_TAG_compile_unit
+ .byte 0                       # DW_CHILDREN_no
+ .byte 16                      # DW_AT_stmt_list
+ .byte 23                      # DW_FORM_sec_offset
+ .ascii "\260B"                # DW_AT_GNU_dwo_name
+ .byte 14                      # DW_FORM_strp
+ .byte 27                      # DW_AT_comp_dir
+ .byte 14                      # DW_FORM_strp
+ .ascii "\264B"                # DW_AT_GNU_pubnames
+ .byte 25                      # DW_FORM_flag_present
+ .ascii "\261B"                # DW_AT_GNU_dwo_id
+ .byte 7                       # DW_FORM_data8
+ .ascii "\263B"                # DW_AT_GNU_addr_base
+ .byte 23                      # DW_FORM_sec_offset
+ .byte 0                       # EOM(1)
+ .byte 0                       # EOM(2)
+ .byte 0                       # EOM(3)
+
+.section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long 32                       # Length of Unit
+ .short 4                       # DWARF version number
+ .long .debug_abbrev            # Offset Into Abbrev. Section
+ .byte 8                        # Address Size (in bytes)
+ .byte 1                        # Abbrev [1] 0xb:0x19 DW_TAG_compile_unit
+ .long 0                        # DW_AT_stmt_list
+ .long 0                        # DW_AT_GNU_dwo_name
+ .long 0                        # DW_AT_comp_dir
+ .quad 0                        # DW_AT_GNU_dwo_id
+ .long 0                        # DW_AT_GNU_addr_base
+
+.section .debug_gnu_pubtypes,"",@progbits
+.long .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info
+.LpubTypes_begin0:
+ .short 2                      # DWARF Version
+ .long .Lcu_begin0             # Offset of Compilation Unit Info
+ .long 36                      # Compilation Unit Length
+ .long 36                      # DIE offset
+ .byte 144                     # Kind: TYPE, STATIC
+ .asciz "int"                  # External Name
+ .long 36                      # DIE offset
+ .byte 144                     # Kind: TYPE, STATIC
+ .asciz "int"                  # External Name
+ .long 0                       # End Mark
+.LpubTypes_end0:
diff --git a/test/ELF/gdb-index-empty.s b/test/ELF/gdb-index-empty.s
new file mode 100644 (file)
index 0000000..0158357
--- /dev/null
@@ -0,0 +1,81 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t %s
+# RUN: ld.lld --gdb-index --gc-sections -o %t2 %t
+# RUN: llvm-dwarfdump -debug-dump=gdb_index %t2 | FileCheck %s
+
+# CHECK: Address area offset = 0x28, has 0 entries:
+
+# Generated with: (clang r302976)
+# echo "void _start() { __builtin_unreachable(); }" | \
+# clang -Os -g -S -o gdb-index-empty.s -x c - -Xclang -fdebug-compilation-dir -Xclang .
+
+.text
+.globl _start
+.type _start,@function
+_start:
+.Lfunc_begin0:
+.Lfunc_end0:
+
+.section .debug_abbrev,"",@progbits
+ .byte 1                       # Abbreviation Code
+ .byte 17                      # DW_TAG_compile_unit
+ .byte 1                       # DW_CHILDREN_yes
+ .byte 37                      # DW_AT_producer
+ .byte 14                      # DW_FORM_strp
+ .byte 19                      # DW_AT_language
+ .byte 5                       # DW_FORM_data2
+ .byte 3                       # DW_AT_name
+ .byte 14                      # DW_FORM_strp
+ .byte 16                      # DW_AT_stmt_list
+ .byte 23                      # DW_FORM_sec_offset
+ .byte 27                      # DW_AT_comp_dir
+ .byte 14                      # DW_FORM_strp
+ .byte 17                      # DW_AT_low_pc
+ .byte 1                       # DW_FORM_addr
+ .byte 18                      # DW_AT_high_pc
+ .byte 6                       # DW_FORM_data4
+ .byte 0                       # EOM(1)
+ .byte 0                       # EOM(2)
+ .byte 2                       # Abbreviation Code
+ .byte 46                      # DW_TAG_subprogram
+ .byte 0                       # DW_CHILDREN_no
+ .byte 17                      # DW_AT_low_pc
+ .byte 1                       # DW_FORM_addr
+ .byte 18                      # DW_AT_high_pc
+ .byte 6                       # DW_FORM_data4
+ .byte 64                      # DW_AT_frame_base
+ .byte 24                      # DW_FORM_exprloc
+ .byte 3                       # DW_AT_name
+ .byte 14                      # DW_FORM_strp
+ .byte 58                      # DW_AT_decl_file
+ .byte 11                      # DW_FORM_data1
+ .byte 59                      # DW_AT_decl_line
+ .byte 11                      # DW_FORM_data1
+ .byte 63                      # DW_AT_external
+ .byte 25                      # DW_FORM_flag_present
+ .byte 0                       # EOM(1)
+ .byte 0                       # EOM(2)
+ .byte 0                       # EOM(3)
+
+.section .debug_info,"",@progbits
+ .long 60                        # Length of Unit
+ .short 4                        # DWARF version number
+ .long .debug_abbrev             # Offset Into Abbrev. Section
+ .byte 8                         # Address Size (in bytes)
+ .byte 1                         # Abbrev [1] 0xb:0x35 DW_TAG_compile_unit
+ .long 0                         # DW_AT_producer
+ .short 12                       # DW_AT_language
+ .long 0                         # DW_AT_name
+ .long 0                         # DW_AT_stmt_list
+ .long 0                         # DW_AT_comp_dir
+ .quad .Lfunc_begin0             # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 2                         # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram
+ .quad .Lfunc_begin0             # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1                         # DW_AT_frame_base
+ .byte 87                        
+ .long 0                         # DW_AT_name
+ .byte 1                         # DW_AT_decl_file
+ .byte 1                         # DW_AT_decl_line
+ .byte 0                         # End Of Children Mark
diff --git a/test/ELF/gdb-index-gc-sections.s b/test/ELF/gdb-index-gc-sections.s
new file mode 100644 (file)
index 0000000..58c47ae
--- /dev/null
@@ -0,0 +1,158 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t %s
+# RUN: ld.lld --gdb-index --gc-sections -o %t2 %t
+# RUN: llvm-dwarfdump -debug-dump=gdb_index %t2 | FileCheck %s
+
+# CHECK: Address area offset = 0x28, has 1 entries:
+# CHECK-NEXT:    Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
+
+# Generated with: (clang r302976)
+# echo "void _start() {} void dead() {}" | \
+# clang -Os -g -S -ffunction-sections -o gdb-index-gc-sections.s -x c - -Xclang -fdebug-compilation-dir -Xclang .
+
+       .text
+       .file   "-"
+       .section        .text._start,"ax",@progbits
+       .globl  _start
+       .type   _start,@function
+_start:                                 # @_start
+.Lfunc_begin0:
+       .file   1 "<stdin>"
+       .loc    1 1 0                   # <stdin>:1:0
+       .cfi_startproc
+# BB#0:                                 # %entry
+       .loc    1 1 16 prologue_end     # <stdin>:1:16
+       retq
+.Ltmp0:
+.Lfunc_end0:
+       .size   _start, .Lfunc_end0-_start
+       .cfi_endproc
+
+       .section        .text.dead,"ax",@progbits
+       .globl  dead
+       .type   dead,@function
+dead:                                   # @dead
+.Lfunc_begin1:
+       .loc    1 1 0                   # <stdin>:1:0
+       .cfi_startproc
+# BB#0:                                 # %entry
+       .loc    1 1 31 prologue_end     # <stdin>:1:31
+       retq
+.Ltmp1:
+.Lfunc_end1:
+       .size   dead, .Lfunc_end1-dead
+       .cfi_endproc
+
+       .section        .debug_str,"MS",@progbits,1
+.Linfo_string0:
+       .asciz  "clang version 5.0.0 "  # string offset=0
+.Linfo_string1:
+       .asciz  "-"                     # string offset=21
+.Linfo_string2:
+       .asciz  "."                     # string offset=23
+.Linfo_string3:
+       .asciz  "_start"                # string offset=25
+.Linfo_string4:
+       .asciz  "dead"                  # string offset=32
+       .section        .debug_loc,"",@progbits
+       .section        .debug_abbrev,"",@progbits
+       .byte   1                       # Abbreviation Code
+       .byte   17                      # DW_TAG_compile_unit
+       .byte   1                       # DW_CHILDREN_yes
+       .byte   37                      # DW_AT_producer
+       .byte   14                      # DW_FORM_strp
+       .byte   19                      # DW_AT_language
+       .byte   5                       # DW_FORM_data2
+       .byte   3                       # DW_AT_name
+       .byte   14                      # DW_FORM_strp
+       .byte   16                      # DW_AT_stmt_list
+       .byte   23                      # DW_FORM_sec_offset
+       .byte   27                      # DW_AT_comp_dir
+       .byte   14                      # DW_FORM_strp
+       .byte   17                      # DW_AT_low_pc
+       .byte   1                       # DW_FORM_addr
+       .byte   85                      # DW_AT_ranges
+       .byte   23                      # DW_FORM_sec_offset
+       .byte   0                       # EOM(1)
+       .byte   0                       # EOM(2)
+       .byte   2                       # Abbreviation Code
+       .byte   46                      # DW_TAG_subprogram
+       .byte   0                       # DW_CHILDREN_no
+       .byte   17                      # DW_AT_low_pc
+       .byte   1                       # DW_FORM_addr
+       .byte   18                      # DW_AT_high_pc
+       .byte   6                       # DW_FORM_data4
+       .byte   64                      # DW_AT_frame_base
+       .byte   24                      # DW_FORM_exprloc
+       .byte   3                       # DW_AT_name
+       .byte   14                      # DW_FORM_strp
+       .byte   58                      # DW_AT_decl_file
+       .byte   11                      # DW_FORM_data1
+       .byte   59                      # DW_AT_decl_line
+       .byte   11                      # DW_FORM_data1
+       .byte   63                      # DW_AT_external
+       .byte   25                      # DW_FORM_flag_present
+       .byte   0                       # EOM(1)
+       .byte   0                       # EOM(2)
+       .byte   0                       # EOM(3)
+       .section        .debug_info,"",@progbits
+.Lcu_begin0:
+       .long   81                      # Length of Unit
+       .short  4                       # DWARF version number
+       .long   .debug_abbrev           # Offset Into Abbrev. Section
+       .byte   8                       # Address Size (in bytes)
+       .byte   1                       # Abbrev [1] 0xb:0x4a DW_TAG_compile_unit
+       .long   .Linfo_string0          # DW_AT_producer
+       .short  12                      # DW_AT_language
+       .long   .Linfo_string1          # DW_AT_name
+       .long   .Lline_table_start0     # DW_AT_stmt_list
+       .long   .Linfo_string2          # DW_AT_comp_dir
+       .quad   0                       # DW_AT_low_pc
+       .long   .Ldebug_ranges0         # DW_AT_ranges
+       .byte   2                       # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram
+       .quad   .Lfunc_begin0           # DW_AT_low_pc
+       .long   .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+       .byte   1                       # DW_AT_frame_base
+       .byte   87
+       .long   .Linfo_string3          # DW_AT_name
+       .byte   1                       # DW_AT_decl_file
+       .byte   1                       # DW_AT_decl_line
+                                        # DW_AT_external
+       .byte   2                       # Abbrev [2] 0x3f:0x15 DW_TAG_subprogram
+       .quad   .Lfunc_begin1           # DW_AT_low_pc
+       .long   .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+       .byte   1                       # DW_AT_frame_base
+       .byte   87
+       .long   .Linfo_string4          # DW_AT_name
+       .byte   1                       # DW_AT_decl_file
+       .byte   1                       # DW_AT_decl_line
+                                        # DW_AT_external
+       .byte   0                       # End Of Children Mark
+       .section        .debug_ranges,"",@progbits
+.Ldebug_ranges0:
+       .quad   .Lfunc_begin0
+       .quad   .Lfunc_end0
+       .quad   .Lfunc_begin1
+       .quad   .Lfunc_end1
+       .quad   0
+       .quad   0
+       .section        .debug_macinfo,"",@progbits
+.Lcu_macro_begin0:
+       .byte   0                       # End Of Macro List Mark
+       .section        .debug_pubnames,"",@progbits
+       .long   .LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info
+.LpubNames_begin0:
+       .short  2                       # DWARF Version
+       .long   .Lcu_begin0             # Offset of Compilation Unit Info
+       .long   85                      # Compilation Unit Length
+       .long   42                      # DIE offset
+       .asciz  "_start"                # External Name
+       .long   63                      # DIE offset
+       .asciz  "dead"                  # External Name
+       .long   0                       # End Mark
+.LpubNames_end0:
+
+       .ident  "clang version 5.0.0 "
+       .section        ".note.GNU-stack","",@progbits
+       .section        .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/test/ELF/gdb-index-ranges.s b/test/ELF/gdb-index-ranges.s
new file mode 100644 (file)
index 0000000..2dd158e
--- /dev/null
@@ -0,0 +1,66 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --gdb-index -e main %t.o -o %t
+# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s
+
+# CHECK:       .gnu_index contents:
+# CHECK:        Address area offset = 0x28, has 2 entries:
+# CHECK-NEXT:     Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
+# CHECK-NEXT:     Low/High address = [0x201001, 0x201003) (Size: 0x2), CU id = 0
+
+.section .text.foo1,"ax",@progbits
+.Lfunc_begin0:
+ nop
+.Lfunc_end0:
+
+.section .text.foo2,"ax",@progbits
+.Lfunc_begin1:
+ nop
+ nop
+.Lfunc_end1:
+
+.section .debug_abbrev,"",@progbits
+.byte 1                       # Abbreviation Code
+.byte 17                      # DW_TAG_compile_unit
+.byte 0                       # DW_CHILDREN_no
+.byte 37                      # DW_AT_producer
+.byte 14                      # DW_FORM_strp
+.byte 19                      # DW_AT_language
+.byte 5                       # DW_FORM_data2
+.byte 3                       # DW_AT_name
+.byte 14                      # DW_FORM_strp
+.byte 16                      # DW_AT_stmt_list
+.byte 23                      # DW_FORM_sec_offset
+.byte 27                      # DW_AT_comp_dir
+.byte 14                      # DW_FORM_strp
+.byte 17                      # DW_AT_low_pc
+.byte 1                       # DW_FORM_addr
+.byte 85                      # DW_AT_ranges
+.byte 23                      # DW_FORM_sec_offset
+.byte 0                       # EOM(1)
+.byte 0                       # EOM(2)
+.byte 0                       # EOM(3)
+
+.section .debug_info,"",@progbits
+.Lcu_begin0:
+.long 38                      # Length of Unit
+.short 4                      # DWARF version number
+.long .debug_abbrev           # Offset Into Abbrev. Section
+.byte 8                       # Address Size (in bytes)
+.byte 1                       # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+.long 0                       # DW_AT_producer
+.short 4                      # DW_AT_language
+.long 0                       # DW_AT_name
+.long 0                       # DW_AT_stmt_list
+.long 0                       # DW_AT_comp_dir
+.quad 0                       # DW_AT_low_pc
+.long .Ldebug_ranges0         # DW_AT_ranges
+
+.section .debug_ranges,"",@progbits
+.Ldebug_ranges0:
+.quad .Lfunc_begin0
+.quad .Lfunc_end0
+.quad .Lfunc_begin1
+.quad .Lfunc_end1
+.quad 0
+.quad 0
diff --git a/test/ELF/gdb-index.s b/test/ELF/gdb-index.s
new file mode 100644 (file)
index 0000000..e04845e
--- /dev/null
@@ -0,0 +1,112 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/gdb-index.s -o %t2.o
+# RUN: ld.lld --gdb-index -e main %t1.o %t2.o -o %t
+# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s
+# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM
+
+# DISASM:       Disassembly of section .text:
+# DISASM:       main:
+# DISASM-CHECK:   201000: 90 nop
+# DISASM-CHECK:   201001: cc int3
+# DISASM-CHECK:   201002: cc int3
+# DISASM-CHECK:   201003: cc int3
+# DISASM:       main2:
+# DISASM-CHECK:   201004: 90 nop
+# DISASM-CHECK:   201005: 90 nop
+
+# CHECK:      .gnu_index contents:
+# CHECK-NEXT:    Version = 7
+# CHECK:       CU list offset = 0x18, has 2 entries:
+# CHECK-NEXT:    0: Offset = 0x0, Length = 0x34
+# CHECK-NEXT:    1: Offset = 0x34, Length = 0x34
+# CHECK:       Address area offset = 0x38, has 2 entries:
+# CHECK-NEXT:    Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
+# CHECK-NEXT:    Low/High address = [0x201004, 0x201006) (Size: 0x2), CU id = 1
+# CHECK:       Symbol table offset = 0x60, size = 1024, filled slots:
+# CHECK-NEXT:    489: Name offset = 0x1d, CU vector offset = 0x0
+# CHECK-NEXT:      String name: main, CU vector index: 0
+# CHECK-NEXT:    754: Name offset = 0x22, CU vector offset = 0x8
+# CHECK-NEXT:      String name: int, CU vector index: 1
+# CHECK-NEXT:    956: Name offset = 0x26, CU vector offset = 0x14
+# CHECK-NEXT:      String name: main2, CU vector index: 2
+# CHECK:       Constant pool offset = 0x2060, has 3 CU vectors:
+# CHECK-NEXT:    0(0x0): 0x30000000
+# CHECK-NEXT:    1(0x8): 0x90000000 0x90000001
+# CHECK-NEXT:    2(0x14): 0x30000001
+
+## The following section contents are created by this using gcc 7.1.0:
+## echo 'int main() { return 0; }' | gcc -gsplit-dwarf -xc++ -S -o- -
+
+.text
+.Ltext0:
+.globl main
+.type main, @function
+main:
+ nop
+.Letext0:
+
+.section .debug_info,"",@progbits
+.long 0x30
+.value 0x4
+.long 0
+.byte 0x8
+.uleb128 0x1
+.quad .Ltext0
+.quad .Letext0-.Ltext0
+.long 0
+.long 0
+.long 0
+.long 0
+.byte 0x63
+.byte 0x88
+.byte 0xb4
+.byte 0x61
+.byte 0xaa
+.byte 0xb6
+.byte 0xb0
+.byte 0x67
+
+.section .debug_abbrev,"",@progbits
+.uleb128 0x1
+.uleb128 0x11
+.byte 0
+.uleb128 0x11
+.uleb128 0x1
+.uleb128 0x12
+.uleb128 0x7
+.uleb128 0x10
+.uleb128 0x17
+.uleb128 0x2130
+.uleb128 0xe
+.uleb128 0x1b
+.uleb128 0xe
+.uleb128 0x2134
+.uleb128 0x19
+.uleb128 0x2133
+.uleb128 0x17
+.uleb128 0x2131
+.uleb128 0x7
+.byte 0
+.byte 0
+.byte 0
+
+.section .debug_gnu_pubnames,"",@progbits
+.long 0x18
+.value 0x2
+.long 0
+.long 0x33
+.long 0x18
+.byte 0x30
+.string "main"
+.long 0
+
+.section .debug_gnu_pubtypes,"",@progbits
+.long 0x17
+.value 0x2
+.long 0
+.long 0x33
+.long 0x2b
+.byte 0x90
+.string "int"
+.long 0
diff --git a/test/ELF/global-offset-table-position-aarch64.s b/test/ELF/global-offset-table-position-aarch64.s
new file mode 100644 (file)
index 0000000..624e9b5
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: aarch64
+.globl  a
+.type   a,@object
+.comm   a,4,4
+
+.globl  f
+.type   f,@function
+f:
+ adrp   x0, :got:a
+ ldr    x0, [x0, #:got_lo12:a]
+
+.global _start
+.type _start,@function
+_start:
+ bl f
+.data
+.long _GLOBAL_OFFSET_TABLE_ - .
+
+// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11)
+// CHECK-NEXT:     Value: 0x30090
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .got
diff --git a/test/ELF/global-offset-table-position-arm.s b/test/ELF/global-offset-table-position-arm.s
new file mode 100644 (file)
index 0000000..781d8ce
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: arm
+
+// The ARM _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
+.globl  a
+.type   a,%object
+.comm   a,4,4
+
+.globl  f
+.type   f,%function
+f:
+ ldr r2, .L1
+.L0:
+ add r2, pc
+.L1:
+.word _GLOBAL_OFFSET_TABLE_ - (.L0+4)
+.word a(GOT)
+
+.global _start
+.type _start,%function
+_start:
+ bl f
+.data
+
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT:     Value: 0x3068
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .got
diff --git a/test/ELF/global-offset-table-position-i386.s b/test/ELF/global-offset-table-position-i386.s
new file mode 100644 (file)
index 0000000..907105e
--- /dev/null
@@ -0,0 +1,31 @@
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
+.globl  a
+.type   a,@object
+.comm   a,4,4
+
+.globl  f
+.type   f,@function
+f:
+addl    $_GLOBAL_OFFSET_TABLE_, %eax
+movl    a@GOT(%eax), %eax
+
+.global _start
+.type _start,@function
+_start:
+addl    $_GLOBAL_OFFSET_TABLE_, %eax
+calll   f@PLT
+
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_ (1)
+// CHECK-NEXT:     Value: 0x306C
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .got (0xA)
diff --git a/test/ELF/global-offset-table-position-mips.s b/test/ELF/global-offset-table-position-mips.s
new file mode 100644 (file)
index 0000000..92daed1
--- /dev/null
@@ -0,0 +1,33 @@
+// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+
+// REQUIRES: mips
+
+// The Mips _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
+
+.globl  a
+.hidden a
+.type   a,@object
+.comm   a,4,4
+
+.globl  f
+.type   f,@function
+f:
+ ld      $v0,%got_page(a)($gp)
+ daddiu  $v0,$v0,%got_ofst(a)
+
+.global _start
+.type _start,@function
+_start:
+ lw      $t0,%call16(f)($gp)
+ .word _GLOBAL_OFFSET_TABLE_ - .
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_ (1)
+// CHECK-NEXT:     Value: 0x20000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .got (0x9)
diff --git a/test/ELF/global-offset-table-position.s b/test/ELF/global-offset-table-position.s
new file mode 100644 (file)
index 0000000..b3317c7
--- /dev/null
@@ -0,0 +1,31 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
+.globl  a
+.type   a,@object
+.comm   a,4,4
+
+.globl  f
+.type   f,@function
+f:
+movq   a@GOTPCREL(%rip), %rax
+
+.global _start
+.type _start,@function
+_start:
+callq  f@PLT
+.data
+.long _GLOBAL_OFFSET_TABLE_ - .
+
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT:     Value: 0x30D8
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other [
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .got
diff --git a/test/ELF/global_offset_table.s b/test/ELF/global_offset_table.s
new file mode 100644 (file)
index 0000000..47e95e9
--- /dev/null
@@ -0,0 +1,5 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+.global _start
+_start:
+.long _GLOBAL_OFFSET_TABLE_
diff --git a/test/ELF/global_offset_table_shared.s b/test/ELF/global_offset_table_shared.s
new file mode 100644 (file)
index 0000000..1ebc011
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+.long _GLOBAL_OFFSET_TABLE_ - .
+
+// CHECK:      Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT: Value: 0x2060
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other [ (0x2)
+// CHECK-NEXT: STV_HIDDEN (0x2)
+// CHECK-NEXT:    ]
+// CHECK-NEXT: Section: .got
diff --git a/test/ELF/gnu-hash-table.s b/test/ELF/gnu-hash-table.s
new file mode 100644 (file)
index 0000000..0e37574
--- /dev/null
@@ -0,0 +1,195 @@
+# REQUIRES: x86,ppc
+
+# RUN: echo ".globl foo" > %te.s
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux      %te.s -o %te-i386.o
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux      %s    -o %t-i386.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux    %s    -o %t-x86_64.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %s    -o %t-ppc64.o
+
+# RUN: ld.lld -shared --hash-style=gnu  -o %te-i386.so  %te-i386.o
+# RUN: ld.lld -shared  -hash-style=gnu  -o %t-i386.so   %t-i386.o
+# RUN: ld.lld -shared  -hash-style=gnu  -o %t-x86_64.so %t-x86_64.o
+# RUN: ld.lld -shared --hash-style both -o %t-ppc64.so  %t-ppc64.o
+
+# RUN: llvm-readobj -dyn-symbols -gnu-hash-table %te-i386.so \
+# RUN:   | FileCheck %s -check-prefix=EMPTY
+# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-i386.so \
+# RUN:   | FileCheck %s -check-prefix=I386
+# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-x86_64.so \
+# RUN:   | FileCheck %s -check-prefix=X86_64
+# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64.so \
+# RUN:   | FileCheck %s -check-prefix=PPC64
+
+# EMPTY:      DynamicSymbols [
+# EMPTY:        Symbol {
+# EMPTY:          Name: foo@
+# EMPTY-NEXT:     Value: 0x0
+# EMPTY-NEXT:     Size: 0
+# EMPTY-NEXT:     Binding: Global
+# EMPTY-NEXT:     Type: None
+# EMPTY-NEXT:     Other: 0
+# EMPTY-NEXT:     Section: Undefined
+# EMPTY-NEXT:   }
+# EMPTY-NEXT: ]
+# EMPTY:      GnuHashTable {
+# EMPTY-NEXT:   Num Buckets: 0
+# EMPTY-NEXT:   First Hashed Symbol Index: 2
+# EMPTY-NEXT:   Num Mask Words: 1
+# EMPTY-NEXT:   Shift Count: 5
+# EMPTY-NEXT:   Bloom Filter: [0x0]
+# EMPTY-NEXT:   Buckets: []
+# EMPTY-NEXT:   Values: []
+# EMPTY-NEXT: }
+
+# I386:      Format: ELF32-i386
+# I386:      Arch: i386
+# I386:      AddressSize: 32bit
+# I386:      Sections [
+# I386:          Name: .gnu.hash
+# I386-NEXT:     Type: SHT_GNU_HASH
+# I386-NEXT:     Flags [
+# I386-NEXT:       SHF_ALLOC
+# I386-NEXT:     ]
+# I386-NEXT:     Address:
+# I386-NEXT:     Offset:
+# I386-NEXT:     Size: 32
+# I386-NEXT:     Link:
+# I386-NEXT:     Info: 0
+# I386-NEXT:     AddressAlignment: 4
+# I386-NEXT:     EntrySize: 0
+# I386:      ]
+# I386:      DynamicSymbols [
+# I386:        Symbol {
+# I386:          Name: @
+# I386:          Binding: Local
+# I386:          Section: Undefined
+# I386:        }
+# I386:        Symbol {
+# I386:          Name: baz@
+# I386:          Binding: Global
+# I386:          Section: Undefined
+# I386:        }
+# I386:        Symbol {
+# I386:          Name: bar@
+# I386:          Binding: Global
+# I386:          Section: .text
+# I386:        }
+# I386:        Symbol {
+# I386:          Name: foo@
+# I386:          Binding: Global
+# I386:          Section: .text
+# I386:        }
+# I386:      ]
+# I386:      GnuHashTable {
+# I386-NEXT:   Num Buckets: 1
+# I386-NEXT:   First Hashed Symbol Index: 2
+# I386-NEXT:   Num Mask Words: 1
+# I386-NEXT:   Shift Count: 5
+# I386-NEXT:   Bloom Filter: [0x14000220]
+# I386-NEXT:   Buckets: [2]
+# I386-NEXT:   Values: [0xB8860BA, 0xB887389]
+# I386-NEXT: }
+
+# X86_64:      Format: ELF64-x86-64
+# X86_64:      Arch: x86_64
+# X86_64:      AddressSize: 64bit
+# X86_64:      Sections [
+# X86_64:          Name: .gnu.hash
+# X86_64-NEXT:     Type: SHT_GNU_HASH
+# X86_64-NEXT:     Flags [
+# X86_64-NEXT:       SHF_ALLOC
+# X86_64-NEXT:     ]
+# X86_64-NEXT:     Address:
+# X86_64-NEXT:     Offset:
+# X86_64-NEXT:     Size: 36
+# X86_64-NEXT:     Link:
+# X86_64-NEXT:     Info: 0
+# X86_64-NEXT:     AddressAlignment: 8
+# X86_64-NEXT:     EntrySize: 0
+# X86_64-NEXT:   }
+# X86_64:      ]
+# X86_64:      DynamicSymbols [
+# X86_64:        Symbol {
+# X86_64:          Name: @
+# X86_64:          Binding: Local
+# X86_64:          Section: Undefined
+# X86_64:        }
+# X86_64:        Symbol {
+# X86_64:          Name: baz@
+# X86_64:          Binding: Global
+# X86_64:          Section: Undefined
+# X86_64:        }
+# X86_64:        Symbol {
+# X86_64:          Name: bar@
+# X86_64:          Binding: Global
+# X86_64:          Section: .text
+# X86_64:        }
+# X86_64:        Symbol {
+# X86_64:          Name: foo@
+# X86_64:          Binding: Global
+# X86_64:          Section: .text
+# X86_64:        }
+# X86_64:      ]
+# X86_64:      GnuHashTable {
+# X86_64-NEXT:   Num Buckets: 1
+# X86_64-NEXT:   First Hashed Symbol Index: 2
+# X86_64-NEXT:   Num Mask Words: 1
+# X86_64-NEXT:   Shift Count: 6
+# X86_64-NEXT:   Bloom Filter: [0x400000000004204]
+# X86_64-NEXT:   Buckets: [2]
+# X86_64-NEXT:   Values: [0xB8860BA, 0xB887389]
+# X86_64-NEXT: }
+
+# PPC64:      Format: ELF64-ppc64
+# PPC64:      Arch: powerpc64
+# PPC64:      AddressSize: 64bit
+# PPC64:      Sections [
+# PPC64:          Name: .gnu.hash
+# PPC64-NEXT:     Type: SHT_GNU_HASH
+# PPC64-NEXT:     Flags [
+# PPC64-NEXT:       SHF_ALLOC
+# PPC64-NEXT:     ]
+# PPC64-NEXT:     Address: 0x228
+# PPC64-NEXT:     Offset: 0x228
+# PPC64-NEXT:     Size: 36
+# PPC64-NEXT:     Link: 1
+# PPC64-NEXT:     Info: 0
+# PPC64-NEXT:     AddressAlignment: 8
+# PPC64-NEXT:     EntrySize: 0
+# PPC64-NEXT:   }
+# PPC64:      ]
+# PPC64:      DynamicSymbols [
+# PPC64:        Symbol {
+# PPC64:          Name: @
+# PPC64:          Binding: Local
+# PPC64:          Section: Undefined
+# PPC64:        }
+# PPC64:        Symbol {
+# PPC64:          Name: baz@
+# PPC64:          Binding: Global
+# PPC64:          Section: Undefined
+# PPC64:        }
+# PPC64:        Symbol {
+# PPC64:          Name: bar@
+# PPC64:          Binding: Global
+# PPC64:          Section: .text
+# PPC64:        }
+# PPC64:        Symbol {
+# PPC64:          Name: foo@
+# PPC64:          Binding: Global
+# PPC64:          Section: .text
+# PPC64:        }
+# PPC64:      ]
+# PPC64:      GnuHashTable {
+# PPC64-NEXT:   Num Buckets: 1
+# PPC64-NEXT:   First Hashed Symbol Index: 2
+# PPC64-NEXT:   Num Mask Words: 1
+# PPC64-NEXT:   Shift Count: 6
+# PPC64-NEXT:   Bloom Filter: [0x400000000004204]
+# PPC64-NEXT:   Buckets: [2]
+# PPC64-NEXT:   Values: [0xB8860BA, 0xB887389]
+# PPC64-NEXT: }
+
+.globl foo,bar,baz
+foo:
+bar:
diff --git a/test/ELF/gnu-ifunc-dso.s b/test/ELF/gnu-ifunc-dso.s
new file mode 100644 (file)
index 0000000..6ceff3b
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-dso.s -o %t1.o
+# RUN: ld.lld -shared %t1.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+# RUN: ld.lld -shared %t2.o %t.so -o %t
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT:   0x1000 R_X86_64_64 foo 0x0
+# CHECK-NEXT: }
+
+.data
+ .quad foo
diff --git a/test/ELF/gnu-ifunc-gotpcrel.s b/test/ELF/gnu-ifunc-gotpcrel.s
new file mode 100644 (file)
index 0000000..2a5814a
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-gotpcrel.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o %t2.so -o %t
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT:   0x2020B0 R_X86_64_GLOB_DAT foo 0x0
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+mov foo@gotpcrel(%rip), %rax
diff --git a/test/ELF/gnu-ifunc-i386.s b/test/ELF/gnu-ifunc-i386.s
new file mode 100644 (file)
index 0000000..21f1313
--- /dev/null
@@ -0,0 +1,126 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Sections [
+// CHECK:       Section {
+// CHECK:       Index: 1
+// CHECK-NEXT:  Name: .rel.plt
+// CHECK-NEXT:  Type: SHT_REL
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: [[RELA:.*]]
+// CHECK-NEXT:  Offset: 0xD4
+// CHECK-NEXT:  Size: 16
+// CHECK-NEXT:  Link: 6
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 4
+// CHECK-NEXT:  EntrySize: 8
+// CHECK-NEXT: }
+// CHECK:     Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.plt {
+// CHECK-NEXT:     0x12000 R_386_IRELATIVE
+// CHECK-NEXT:     0x12004 R_386_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Symbols [
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name:
+// CHECK-NEXT:   Value: 0x0
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: Undefined
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __rel_iplt_end
+// CHECK-NEXT:   Value: 0x100E4
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .rel.plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __rel_iplt_start
+// CHECK-NEXT:   Value: [[RELA]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .rel.plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: _start
+// CHECK-NEXT:   Value: 0x11002
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: bar
+// CHECK-NEXT:   Value: 0x11001
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: GNU_IFunc
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: foo
+// CHECK-NEXT:   Value: 0x11000
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: GNU_IFunc
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT:]
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    11000: c3 retl
+// DISASM: bar:
+// DISASM-NEXT:    11001: c3 retl
+// DISASM:      _start:
+// DISASM-NEXT:    11002: e8 19 00 00 00 calll 25
+// DISASM-NEXT:    11007: e8 24 00 00 00 calll 36
+// DISASM-NEXT:    1100c: ba d4 00 01 00 movl $65748, %edx
+// DISASM-NEXT:    11011: ba e4 00 01 00 movl $65764, %edx
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    11020: ff 25 00 20 01 00 jmpl *73728
+// DISASM-NEXT:    11026: 68 10 00 00 00 pushl $16
+// DISASM-NEXT:    1102b: e9 e0 ff ff ff jmp -32 <_start+0xE>
+// DISASM-NEXT:    11030: ff 25 04 20 01 00 jmpl *73732
+// DISASM-NEXT:    11036: 68 18 00 00 00 pushl $24
+// DISASM-NEXT:    1103b: e9 d0 ff ff ff jmp -48 <_start+0xE>
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ movl $__rel_iplt_start,%edx
+ movl $__rel_iplt_end,%edx
diff --git a/test/ELF/gnu-ifunc-nosym-i386.s b/test/ELF/gnu-ifunc-nosym-i386.s
new file mode 100644 (file)
index 0000000..d22cedb
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that no __rel_iplt_end/__rel_iplt_start
+// appear in symtab if there is no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rel_iplt_end
+// CHECK-NOT: __rel_iplt_start
+// CHECK: ]
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
diff --git a/test/ELF/gnu-ifunc-nosym.s b/test/ELF/gnu-ifunc-nosym.s
new file mode 100644 (file)
index 0000000..08e498e
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that no __rela_iplt_end/__rela_iplt_start
+// appear in symtab if there is no references to them.
+// CHECK:      Symbols [
+// CHECK-NOT: __rela_iplt_end
+// CHECK-NOT: __rela_iplt_start
+// CHECK: ]
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
diff --git a/test/ELF/gnu-ifunc-plt-i386.s b/test/ELF/gnu-ifunc-plt-i386.s
new file mode 100644 (file)
index 0000000..50f10c5
--- /dev/null
@@ -0,0 +1,76 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rel.plt {
+// CHECK-NEXT:     0x1200C R_386_JUMP_SLOT bar2
+// CHECK-NEXT:     0x12010 R_386_JUMP_SLOT zed2
+// CHECK-NEXT:     0x12014 R_386_IRELATIVE
+// CHECK-NEXT:     0x12018 R_386_IRELATIVE
+
+// Check that IRELATIVE .got.plt entries point to ifunc resolver and not
+// back to the plt entry + 6.
+// GOTPLT: Contents of section .got.plt:
+// GOTPLT:       12000 00300100 00000000 00000000 36100100
+// GOTPLT-NEXT:  12010 46100100 00100100 01100100
+
+// Check that the PLTRELSZ tag includes the IRELATIVE relocations
+// CHECK: DynamicSection [
+// CHECK:  0x00000002 PLTRELSZ             32 (bytes)
+
+// Check that a PLT header is written and the ifunc entries appear last
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    11000:       c3      retl
+// DISASM:      bar:
+// DISASM-NEXT:    11001:       c3      retl
+// DISASM:      _start:
+// DISASM-NEXT:    11002:       e8 49 00 00 00          calll   73
+// DISASM-NEXT:    11007:       e8 54 00 00 00          calll   84
+// DISASM-NEXT:    1100c:       e8 1f 00 00 00          calll   31
+// DISASM-NEXT:    11011:       e8 2a 00 00 00          calll   42
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    11020:       ff 35 04 20 01 00       pushl   73732
+// DISASM-NEXT:    11026:       ff 25 08 20 01 00       jmpl    *73736
+// DISASM-NEXT:    1102c:       90      nop
+// DISASM-NEXT:    1102d:       90      nop
+// DISASM-NEXT:    1102e:       90      nop
+// DISASM-NEXT:    1102f:       90      nop
+// DISASM-NEXT:    11030:       ff 25 0c 20 01 00       jmpl    *73740
+// DISASM-NEXT:    11036:       68 00 00 00 00          pushl   $0
+// DISASM-NEXT:    1103b:       e9 e0 ff ff ff          jmp     -32 <.plt>
+// DISASM-NEXT:    11040:       ff 25 10 20 01 00       jmpl    *73744
+// DISASM-NEXT:    11046:       68 08 00 00 00          pushl   $8
+// DISASM-NEXT:    1104b:       e9 d0 ff ff ff          jmp     -48 <.plt>
+// DISASM-NEXT:    11050:       ff 25 14 20 01 00       jmpl    *73748
+// DISASM-NEXT:    11056:       68 30 00 00 00          pushl   $48
+// DISASM-NEXT:    1105b:       e9 e0 ff ff ff          jmp     -32 <.plt+0x20>
+// DISASM-NEXT:    11060:       ff 25 18 20 01 00       jmpl    *73752
+// DISASM-NEXT:    11066:       68 38 00 00 00          pushl   $56
+// DISASM-NEXT:    1106b:       e9 d0 ff ff ff          jmp     -48 <.plt+0x20>
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ call bar2
+ call zed2
diff --git a/test/ELF/gnu-ifunc-plt.s b/test/ELF/gnu-ifunc-plt.s
new file mode 100644 (file)
index 0000000..cf46380
--- /dev/null
@@ -0,0 +1,74 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rela.plt {
+// CHECK-NEXT:     0x202018 R_X86_64_JUMP_SLOT bar2 0x0
+// CHECK-NEXT:     0x202020 R_X86_64_JUMP_SLOT zed2 0x0
+// CHECK-NEXT:     0x202028 R_X86_64_IRELATIVE - 0x201000
+// CHECK-NEXT:     0x202030 R_X86_64_IRELATIVE - 0x201001
+
+// Check that .got.plt entries point back to PLT header
+// GOTPLT: Contents of section .got.plt:
+// GOTPLT-NEXT:  202000 00302000 00000000 00000000 00000000
+// GOTPLT-NEXT:  202010 00000000 00000000 36102000 00000000
+// GOTPLT-NEXT:  202020 46102000 00000000 56102000 00000000
+// GOTPLT-NEXT:  202030 66102000 00000000
+
+// Check that the PLTRELSZ tag includes the IRELATIVE relocations
+// CHECK: DynamicSection [
+// CHECK:   0x0000000000000002 PLTRELSZ             96 (bytes)
+
+// Check that a PLT header is written and the ifunc entries appear last
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:   201000:       c3      retq
+// DISASM:      bar:
+// DISASM-NEXT:   201001:       c3      retq
+// DISASM:      _start:
+// DISASM-NEXT:   201002:       e8 49 00 00 00          callq   73
+// DISASM-NEXT:   201007:       e8 54 00 00 00          callq   84
+// DISASM-NEXT:   20100c:       e8 1f 00 00 00          callq   31
+// DISASM-NEXT:   201011:       e8 2a 00 00 00          callq   42
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:   201020:       ff 35 e2 0f 00 00       pushq   4066(%rip)
+// DISASM-NEXT:   201026:       ff 25 e4 0f 00 00       jmpq    *4068(%rip)
+// DISASM-NEXT:   20102c:       0f 1f 40 00     nopl    (%rax)
+// DISASM-NEXT:   201030:       ff 25 e2 0f 00 00       jmpq    *4066(%rip)
+// DISASM-NEXT:   201036:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:   20103b:       e9 e0 ff ff ff          jmp     -32 <.plt>
+// DISASM-NEXT:   201040:       ff 25 da 0f 00 00       jmpq    *4058(%rip)
+// DISASM-NEXT:   201046:       68 01 00 00 00          pushq   $1
+// DISASM-NEXT:   20104b:       e9 d0 ff ff ff          jmp     -48 <.plt>
+// DISASM-NEXT:   201050:       ff 25 d2 0f 00 00       jmpq    *4050(%rip)
+// DISASM-NEXT:   201056:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:   20105b:       e9 e0 ff ff ff          jmp     -32 <.plt+0x20>
+// DISASM-NEXT:   201060:       ff 25 ca 0f 00 00       jmpq    *4042(%rip)
+// DISASM-NEXT:   201066:       68 01 00 00 00          pushq   $1
+// DISASM-NEXT:   20106b:       e9 d0 ff ff ff          jmp     -48 <.plt+0x20>
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ call bar2
+ call zed2
diff --git a/test/ELF/gnu-ifunc-relative.s b/test/ELF/gnu-ifunc-relative.s
new file mode 100644 (file)
index 0000000..dc35102
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -r -t %tout | FileCheck %s
+// REQUIRES: x86
+
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.globl _start
+_start:
+ call foo
+
+// CHECK:      Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:   R_X86_64_IRELATIVE - 0x[[ADDR:.*]]
+// CHECK-NEXT: }
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x[[ADDR]]
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: GNU_IFunc
diff --git a/test/ELF/gnu-ifunc-shared.s b/test/ELF/gnu-ifunc-shared.s
new file mode 100644 (file)
index 0000000..aee870c
--- /dev/null
@@ -0,0 +1,66 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld --shared -o %t.so %t.o
+// RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r %t.so | FileCheck %s
+
+// Check that an IRELATIVE relocation is used for a non-preemptible ifunc
+// handler and a JUMP_SLOT is used for a preemptible ifunc
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: fct:
+// DISASM-NEXT:     1000:       c3      retq
+// DISASM:     fct2:
+// DISASM-NEXT:     1001:       c3      retq
+// DISASM:     f1:
+// DISASM-NEXT:     1002:       e8 49 00 00 00          callq   73
+// DISASM-NEXT:     1007:       e8 24 00 00 00          callq   36
+// DISASM-NEXT:     100c:       e8 2f 00 00 00          callq   47
+// DISASM-NEXT:     1011:       c3      retq
+// DISASM:     f2:
+// DISASM-NEXT:     1012:       c3      retq
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:     1020:       ff 35 e2 0f 00 00       pushq   4066(%rip)
+// DISASM-NEXT:     1026:       ff 25 e4 0f 00 00       jmpq    *4068(%rip)
+// DISASM-NEXT:     102c:       0f 1f 40 00     nopl    (%rax)
+// DISASM-NEXT:     1030:       ff 25 e2 0f 00 00       jmpq    *4066(%rip)
+// DISASM-NEXT:     1036:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:     103b:       e9 e0 ff ff ff          jmp     -32 <.plt>
+// DISASM-NEXT:     1040:       ff 25 da 0f 00 00       jmpq    *4058(%rip)
+// DISASM-NEXT:     1046:       68 01 00 00 00          pushq   $1
+// DISASM-NEXT:     104b:       e9 d0 ff ff ff          jmp     -48 <.plt>
+// DISASM-NEXT:     1050:       ff 25 d2 0f 00 00       jmpq    *4050(%rip)
+// DISASM-NEXT:     1056:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:     105b:       e9 e0 ff ff ff          jmp     -32 <.plt+0x20>
+
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rela.plt {
+// CHECK-NEXT:     0x2018 R_X86_64_JUMP_SLOT fct2 0x0
+// CHECK-NEXT:     0x2020 R_X86_64_JUMP_SLOT f2 0x0
+// CHECK-NEXT:     0x2028 R_X86_64_IRELATIVE - 0x1000
+
+ // Hidden expect IRELATIVE
+ .globl fct
+ .hidden fct
+ .type  fct, STT_GNU_IFUNC
+fct:
+ ret
+
+ // Not hidden expect JUMP_SLOT
+ .globl fct2
+ .type  fct2, STT_GNU_IFUNC
+fct2:
+ ret
+
+ .globl f1
+ .type f1, @function
+f1:
+ call fct
+ call fct2
+ call f2@PLT
+ ret
+
+ .globl f2
+ .type f2, @function
+f2:
+ ret
diff --git a/test/ELF/gnu-ifunc.s b/test/ELF/gnu-ifunc.s
new file mode 100644 (file)
index 0000000..f86f030
--- /dev/null
@@ -0,0 +1,127 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Sections [
+// CHECK:       Section {
+// CHECK:       Index: 1
+// CHECK-NEXT:  Name: .rela.plt
+// CHECK-NEXT:  Type: SHT_RELA
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:    SHF_ALLOC
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: [[RELA:.*]]
+// CHECK-NEXT:  Offset: 0x158
+// CHECK-NEXT:  Size: 48
+// CHECK-NEXT:  Link: 6
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 8
+// CHECK-NEXT:  EntrySize: 24
+// CHECK-NEXT: }
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x202000 R_X86_64_IRELATIVE
+// CHECK-NEXT:     0x202008 R_X86_64_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:      Symbols [
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name:
+// CHECK-NEXT:    Value: 0x0
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: Undefined
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_end
+// CHECK-NEXT:    Value: 0x200188
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: __rela_iplt_start
+// CHECK-NEXT:    Value: [[RELA]]
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Local
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other [
+// CHECK-NEXT:      STV_HIDDEN
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Section: .rela.plt
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: _start
+// CHECK-NEXT:    Value: 0x201002
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: None
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: bar
+// CHECK-NEXT:    Value: 0x201001
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: foo
+// CHECK-NEXT:    Value: 0x201000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: GNU_IFunc
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text
+// CHECK-NEXT:  }
+// CHECK-NEXT: ]
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:  201000: {{.*}} retq
+// DISASM:      bar:
+// DISASM-NEXT:  201001: {{.*}} retq
+// DISASM:      _start:
+// DISASM-NEXT:  201002: {{.*}} callq 25
+// DISASM-NEXT:  201007: {{.*}} callq 36
+// DISASM-NEXT:  20100c: {{.*}} movl $2097496, %edx
+// DISASM-NEXT:  201011: {{.*}} movl $2097544, %edx
+// DISASM-NEXT:  201016: {{.*}} movl $2097545, %edx
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:  201020: {{.*}} jmpq *4058(%rip)
+// DISASM-NEXT:  201026: {{.*}} pushq $0
+// DISASM-NEXT:  20102b: {{.*}} jmp -32 <_start+0xE>
+// DISASM-NEXT:  201030: {{.*}} jmpq *4050(%rip)
+// DISASM-NEXT:  201036: {{.*}} pushq $1
+// DISASM-NEXT:  20103b: {{.*}} jmp -48 <_start+0xE>
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ movl $__rela_iplt_start,%edx
+ movl $__rela_iplt_end,%edx
+ movl $__rela_iplt_end + 1,%edx
diff --git a/test/ELF/gnu-unique.s b/test/ELF/gnu-unique.s
new file mode 100644 (file)
index 0000000..afc0da2
--- /dev/null
@@ -0,0 +1,37 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+//
+// RUN: ld.lld %t -shared -o %tout.so
+// RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=GNU %s
+//
+// RUN: ld.lld %t -shared -o %tout.so --no-gnu-unique
+// RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=NO %s
+
+// Check that STB_GNU_UNIQUE is treated as a global and ends up in the dynamic
+// symbol table as STB_GNU_UNIQUE.
+
+.global _start
+.text
+_start:
+
+.data
+.type symb, @gnu_unique_object
+symb:
+
+# GNU:        Name: symb@
+# GNU-NEXT:   Value:
+# GNU-NEXT:   Size: 0
+# GNU-NEXT:   Binding: Unique
+# GNU-NEXT:   Type: Object
+# GNU-NEXT:   Other: 0
+# GNU-NEXT:   Section: .data
+# GNU-NEXT: }
+
+# NO:        Name: symb@
+# NO-NEXT:   Value:
+# NO-NEXT:   Size: 0
+# NO-NEXT:   Binding: Global
+# NO-NEXT:   Type: Object
+# NO-NEXT:   Other: 0
+# NO-NEXT:   Section: .data
+# NO-NEXT: }
diff --git a/test/ELF/gnustack.s b/test/ELF/gnustack.s
new file mode 100644 (file)
index 0000000..c506fb8
--- /dev/null
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: ld.lld %t1 -z execstack -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RWX %s
+# RUN: ld.lld %t1 -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s
+
+# RW:      Type: PT_GNU_STACK
+# RW-NEXT: Offset: 0x0
+# RW-NEXT: VirtualAddress: 0x0
+# RW-NEXT: PhysicalAddress: 0x0
+# RW-NEXT: FileSize: 0
+# RW-NEXT: MemSize: 0
+# RW-NEXT: Flags [
+# RW-NEXT:   PF_R
+# RW-NEXT:   PF_W
+# RW-NEXT: ]
+# RW-NEXT: Alignment: 0
+
+# RWX:      Type: PT_GNU_STACK
+# RWX-NEXT: Offset: 0x0
+# RWX-NEXT: VirtualAddress: 0x0
+# RWX-NEXT: PhysicalAddress: 0x0
+# RWX-NEXT: FileSize: 0
+# RWX-NEXT: MemSize: 0
+# RWX-NEXT: Flags [
+# RWX-NEXT:   PF_R
+# RWX-NEXT:   PF_W
+# RWX-NEXT:   PF_X
+# RWX-NEXT: ]
+# RWX-NEXT: Alignment: 0
+
+.globl _start
+_start:
diff --git a/test/ELF/got-aarch64.s b/test/ELF/got-aarch64.s
new file mode 100644 (file)
index 0000000..ef69438
--- /dev/null
@@ -0,0 +1,40 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -s -r %t.so | FileCheck %s
+// RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s
+// REQUIRES: aarch64
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x30090
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x30090 R_AARCH64_GLOB_DAT dat 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Page(0x20098) - Page(0x10000) = 0x10000 = 65536
+// 0x20098 & 0xff8 = 0x98 = 152
+
+// DISASM: main:
+// DISASM-NEXT:   10000:  00 01 00 90   adrp  x0, #131072
+// DISASM-NEXT:   10004: 00 48 40 f9   ldr x0, [x0, #144]
+
+.global main,foo,dat
+.text
+main:
+    adrp x0, :got:dat
+    ldr x0, [x0, :got_lo12:dat]
+.data
+dat:
+    .word 42
diff --git a/test/ELF/got-i386.s b/test/ELF/got-i386.s
new file mode 100644 (file)
index 0000000..679eb2e
--- /dev/null
@@ -0,0 +1,56 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s -r -t %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+
+// CHECK:      Symbol {
+// CHECK:       Name: bar
+// CHECK-NEXT:  Value: 0x12000
+// CHECK-NEXT:  Size: 10
+// CHECK-NEXT:  Binding: Global
+// CHECK-NEXT:  Type: Object
+// CHECK-NEXT:  Other: 0
+// CHECK-NEXT:  Section: .bss
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:  Name: obj
+// CHECK-NEXT:  Value: 0x1200A
+// CHECK-NEXT:  Size: 10
+// CHECK-NEXT:  Binding: Global
+// CHECK-NEXT:  Type: Object
+// CHECK-NEXT:  Other: 0
+// CHECK-NEXT:  Section: .bss
+// CHECK-NEXT: }
+
+// 0x12000 - 0 = addr(.got) = 0x12000
+// 0x1200A - 10 = addr(.got) = 0x12000
+// 0x1200A + 5 - 15 = addr(.got) = 0x12000
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 11000: c7 81 00 00 00 00 01 00 00 00 movl $1, (%ecx)
+// DISASM-NEXT: 1100a: c7 81 0a 00 00 00 02 00 00 00 movl $2, 10(%ecx)
+// DISASM-NEXT: 11014: c7 81 0f 00 00 00 03 00 00 00 movl $3, 15(%ecx)
+
+.global _start
+_start:
+  movl $1, bar@GOTOFF(%ecx)
+  movl $2, obj@GOTOFF(%ecx)
+  movl $3, obj+5@GOTOFF(%ecx)
+  .type bar, @object
+  .comm bar, 10
+  .type obj, @object
+  .comm obj, 10
diff --git a/test/ELF/got-plt-header.s b/test/ELF/got-plt-header.s
new file mode 100644 (file)
index 0000000..a6b10fa
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+        call foo@plt
+
+// Check that the first .got.plt entry has the address of the dynamic table.
+
+// CHECK:      Name: .got.plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00300000 00000000 00000000 00000000
+
+// CHECK:      Type: SHT_DYNAMIC
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x3000
diff --git a/test/ELF/got.s b/test/ELF/got.s
new file mode 100644 (file)
index 0000000..57c1bad
--- /dev/null
@@ -0,0 +1,45 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2020B0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2020B0 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT:     0x2020B8 R_X86_64_GLOB_DAT zed 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+//  0x2020B0 - (0x201000 + 2) - 4 = 4266
+//  0x2020B0 - (0x201006 + 2) - 4 = 4260
+//  0x2020A8 - (0x20100c + 2) - 4 = 4262
+
+// DISASM:      _start:
+// DISASM-NEXT:  201000:  {{.*}}  jmpq  *4266(%rip)
+// DISASM-NEXT:  201006:  {{.*}}  jmpq  *4260(%rip)
+// DISASM-NEXT:  20100c:  {{.*}}  jmpq  *4262(%rip)
+
+.global _start
+_start:
+  jmp *bar@GOTPCREL(%rip)
+  jmp *bar@GOTPCREL(%rip)
+  jmp *zed@GOTPCREL(%rip)
diff --git a/test/ELF/got32-i386.s b/test/ELF/got32-i386.s
new file mode 100644 (file)
index 0000000..468aaf1
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -section-headers -d %t | FileCheck %s
+
+## We have R_386_GOT32 relocation here.
+.globl foo
+.type foo, @function
+foo:
+ nop
+
+_start:
+ movl foo@GOT, %ebx
+
+## 73728 == 0x12000 == ADDR(.got)
+# CHECK:       _start:
+# CHECK-NEXT:   11001: 8b 1d {{.*}}  movl 73728, %ebx
+# CHECK: Sections:
+# CHECK:  Name Size     Address
+# CHECK:  .got 00000004 0000000000012000
+
+# RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s --check-prefix=ERR
+# ERR: relocation R_386_GOT32 against 'foo' without base register can not be used when PIC enabled
diff --git a/test/ELF/got32x-i386.s b/test/ELF/got32x-i386.s
new file mode 100644 (file)
index 0000000..9a67d19
--- /dev/null
@@ -0,0 +1,47 @@
+# REQUIRES: x86
+
+## i386-got32x-baseless.elf is a file produced using GNU as v.2.27
+## using following code and command line:
+## (as --32 -o base.o base.s)
+##
+## .text
+## .globl foo
+## .type foo, @function
+## foo:
+##  nop
+##
+## _start:
+##  movl foo@GOT, %eax
+##  movl foo@GOT, %ebx
+##  movl foo@GOT(%eax), %eax
+##  movl foo@GOT(%ebx), %eax
+##
+## Result file contains four R_386_GOT32X relocations. Generated code
+## is also a four mov instructions. And first two has no base register:
+## <_start>:
+##   1: 8b 05 00 00 00 00 mov 0x0,%eax
+##   7: 8b 1d 00 00 00 00 mov 0x0,%ebx
+##   d: 8b 80 00 00 00 00 mov 0x0(%eax),%eax
+##  13: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax
+##
+## R_386_GOT32X is computed as G + A - GOT, but if it used without base
+## register, it should be calculated as G + A. Using without base register
+## is only allowed for non-PIC code.
+##
+# RUN: ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1
+# RUN: llvm-objdump -section-headers -d %t1 | FileCheck %s
+
+## 73728 == 0x12000 == ADDR(.got)
+# CHECK:       _start:
+# CHECK-NEXT:   11001: 8b 05 {{.*}} movl 73728, %eax
+# CHECK-NEXT:   11007: 8b 1d {{.*}} movl 73728, %ebx
+# CHECK-NEXT:   1100d: 8b 80 {{.*}} movl -4(%eax), %eax
+# CHECK-NEXT:   11013: 8b 83 {{.*}} movl -4(%ebx), %eax
+# CHECK: Sections:
+# CHECK:  Name Size     Address
+# CHECK:  .got 00000004 0000000000012000
+
+# RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ERR
+# ERR: relocation R_386_GOT32X against 'foo' without base register can not be used when PIC enabled
+# ERR: relocation R_386_GOT32X against 'foo' without base register can not be used when PIC enabled
diff --git a/test/ELF/gotpc-relax-nopic.s b/test/ELF/gotpc-relax-nopic.s
new file mode 100644 (file)
index 0000000..dc7dcf2
--- /dev/null
@@ -0,0 +1,87 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1
+# RUN: llvm-readobj -symbols -r %t1 | FileCheck --check-prefix=SYMRELOC %s
+# RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+## There is no relocations.
+# SYMRELOC:      Relocations [
+# SYMRELOC-NEXT: ]
+# SYMRELOC:      Symbols [
+# SYMRELOC:       Symbol {
+# SYMRELOC:        Name: bar
+# SYMRELOC-NEXT:   Value: 0x202000
+
+## 2105344 = 0x202000 (bar)
+# DISASM:      Disassembly of section .text:
+# DISASM-NEXT: _start:
+# DISASM-NEXT:   201000: {{.*}} adcq  $2105344, %rax
+# DISASM-NEXT:   201007: {{.*}} addq  $2105344, %rbx
+# DISASM-NEXT:   20100e: {{.*}} andq  $2105344, %rcx
+# DISASM-NEXT:   201015: {{.*}} cmpq  $2105344, %rdx
+# DISASM-NEXT:   20101c: {{.*}} orq   $2105344, %rdi
+# DISASM-NEXT:   201023: {{.*}} sbbq  $2105344, %rsi
+# DISASM-NEXT:   20102a: {{.*}} subq  $2105344, %rbp
+# DISASM-NEXT:   201031: {{.*}} xorq  $2105344, %r8
+# DISASM-NEXT:   201038: {{.*}} testq $2105344, %r15
+
+# RUN: ld.lld -shared %t.o -o %t2
+# RUN: llvm-readobj -s -r -d %t2 | FileCheck --check-prefix=SEC-PIC    %s
+# RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM-PIC %s
+# SEC-PIC:      Section {
+# SEC-PIC:        Index:
+# SEC-PIC:        Name: .got
+# SEC-PIC-NEXT:   Type: SHT_PROGBITS
+# SEC-PIC-NEXT:   Flags [
+# SEC-PIC-NEXT:     SHF_ALLOC
+# SEC-PIC-NEXT:     SHF_WRITE
+# SEC-PIC-NEXT:   ]
+# SEC-PIC-NEXT:   Address: 0x30A0
+# SEC-PIC-NEXT:   Offset: 0x30A0
+# SEC-PIC-NEXT:   Size: 8
+# SEC-PIC-NEXT:   Link:
+# SEC-PIC-NEXT:   Info:
+# SEC-PIC-NEXT:   AddressAlignment:
+# SEC-PIC-NEXT:   EntrySize:
+# SEC-PIC-NEXT: }
+# SEC-PIC:      Relocations [
+# SEC-PIC-NEXT:   Section ({{.*}}) .rela.dyn {
+# SEC-PIC-NEXT:     0x30A0 R_X86_64_RELATIVE - 0x2000
+# SEC-PIC-NEXT:   }
+# SEC-PIC-NEXT: ]
+# SEC-PIC:      0x000000006FFFFFF9 RELACOUNT            1
+
+## Check that there was no relaxation performed. All values refer to got entry.
+## Ex: 0x1000 + 4249 + 7 = 0x20A0
+##     0x102a + 4207 + 7 = 0x20A0
+# DISASM-PIC:      Disassembly of section .text:
+# DISASM-PIC-NEXT: _start:
+# DISASM-PIC-NEXT: 1000: {{.*}} adcq  8345(%rip), %rax
+# DISASM-PIC-NEXT: 1007: {{.*}} addq  8338(%rip), %rbx
+# DISASM-PIC-NEXT: 100e: {{.*}} andq  8331(%rip), %rcx
+# DISASM-PIC-NEXT: 1015: {{.*}} cmpq  8324(%rip), %rdx
+# DISASM-PIC-NEXT: 101c: {{.*}} orq   8317(%rip), %rdi
+# DISASM-PIC-NEXT: 1023: {{.*}} sbbq  8310(%rip), %rsi
+# DISASM-PIC-NEXT: 102a: {{.*}} subq  8303(%rip), %rbp
+# DISASM-PIC-NEXT: 1031: {{.*}} xorq  8296(%rip), %r8
+# DISASM-PIC-NEXT: 1038: {{.*}} testq 8289(%rip), %r15
+
+.data
+.type   bar, @object
+bar:
+ .byte   1
+ .size   bar, .-bar
+
+.text
+.globl  _start
+.type   _start, @function
+_start:
+  adcq    bar@GOTPCREL(%rip), %rax
+  addq    bar@GOTPCREL(%rip), %rbx
+  andq    bar@GOTPCREL(%rip), %rcx
+  cmpq    bar@GOTPCREL(%rip), %rdx
+  orq     bar@GOTPCREL(%rip), %rdi
+  sbbq    bar@GOTPCREL(%rip), %rsi
+  subq    bar@GOTPCREL(%rip), %rbp
+  xorq    bar@GOTPCREL(%rip), %r8
+  testq   %r15, bar@GOTPCREL(%rip)
diff --git a/test/ELF/gotpc-relax-und-dso.s b/test/ELF/gotpc-relax-und-dso.s
new file mode 100644 (file)
index 0000000..ed6c4bc
--- /dev/null
@@ -0,0 +1,72 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux %S/Inputs/gotpc-relax-und-dso.s -o %tdso.o
+# RUN: ld.lld -shared %tdso.o -o %t.so
+# RUN: ld.lld -shared %t.o %t.so -o %tout
+# RUN: llvm-readobj -r -s %tout | FileCheck --check-prefix=RELOC %s
+# RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s
+
+# RELOC:      Relocations [
+# RELOC-NEXT:   Section ({{.*}}) .rela.dyn {
+# RELOC-NEXT:     R_X86_64_GLOB_DAT dsofoo 0x0
+# RELOC-NEXT:     R_X86_64_GLOB_DAT foo 0x0
+# RELOC-NEXT:     R_X86_64_GLOB_DAT und 0x0
+# RELOC-NEXT:   }
+# RELOC-NEXT: ]
+
+# 0x101e + 7 - 36 = 0x1001
+# 0x1025 + 7 - 43 = 0x1001
+# DISASM:      Disassembly of section .text:
+# DISASM-NEXT: foo:
+# DISASM-NEXT:     nop
+# DISASM:      hid:
+# DISASM-NEXT:     nop
+# DISASM:      _start:
+# DISASM-NEXT:    movq    4247(%rip), %rax
+# DISASM-NEXT:    movq    4240(%rip), %rax
+# DISASM-NEXT:    movq    4241(%rip), %rax
+# DISASM-NEXT:    movq    4234(%rip), %rax
+# DISASM-NEXT:    leaq    -36(%rip), %rax
+# DISASM-NEXT:    leaq    -43(%rip), %rax
+# DISASM-NEXT:    movq    4221(%rip), %rax
+# DISASM-NEXT:    movq    4214(%rip), %rax
+# DISASM-NEXT:    movq    4191(%rip), %rax
+# DISASM-NEXT:    movq    4184(%rip), %rax
+# DISASM-NEXT:    movq    4185(%rip), %rax
+# DISASM-NEXT:    movq    4178(%rip), %rax
+# DISASM-NEXT:    leaq    -92(%rip), %rax
+# DISASM-NEXT:    leaq    -99(%rip), %rax
+# DISASM-NEXT:    movq    4165(%rip), %rax
+# DISASM-NEXT:    movq    4158(%rip), %rax
+
+.text
+.globl foo
+.type foo, @function
+foo:
+ nop
+
+.globl hid
+.hidden hid
+.type hid, @function
+hid:
+ nop
+
+.globl _start
+.type _start, @function
+_start:
+ movq und@GOTPCREL(%rip), %rax
+ movq und@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq und@GOTPCREL(%rip), %rax
+ movq und@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq dsofoo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
diff --git a/test/ELF/gotpc-relax.s b/test/ELF/gotpc-relax.s
new file mode 100644 (file)
index 0000000..3d2f2ab
--- /dev/null
@@ -0,0 +1,98 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1
+# RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOC %s
+# RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+## There is no relocations.
+# RELOC:    Relocations [
+# RELOC:    ]
+
+# 0x201003 + 7 - 10 = 0x201000
+# 0x20100a + 7 - 17 = 0x201000
+# 0x201011 + 7 - 23 = 0x201001
+# 0x201018 + 7 - 30 = 0x201001
+# DISASM:      Disassembly of section .text:
+# DISASM-NEXT: foo:
+# DISASM-NEXT:   201000: 90 nop
+# DISASM:      hid:
+# DISASM-NEXT:   201001: 90 nop
+# DISASM:      ifunc:
+# DISASM-NEXT:   201002: c3 retq
+# DISASM:      _start:
+# DISASM-NEXT: leaq -10(%rip), %rax
+# DISASM-NEXT: leaq -17(%rip), %rax
+# DISASM-NEXT: leaq -23(%rip), %rax
+# DISASM-NEXT: leaq -30(%rip), %rax
+# DISASM-NEXT: movq 4058(%rip), %rax
+# DISASM-NEXT: movq 4051(%rip), %rax
+# DISASM-NEXT: leaq -52(%rip), %rax
+# DISASM-NEXT: leaq -59(%rip), %rax
+# DISASM-NEXT: leaq -65(%rip), %rax
+# DISASM-NEXT: leaq -72(%rip), %rax
+# DISASM-NEXT: movq 4016(%rip), %rax
+# DISASM-NEXT: movq 4009(%rip), %rax
+# DISASM-NEXT: callq -93 <foo>
+# DISASM-NEXT: callq -99 <foo>
+# DISASM-NEXT: callq -104 <hid>
+# DISASM-NEXT: callq -110 <hid>
+# DISASM-NEXT: callq *3979(%rip)
+# DISASM-NEXT: callq *3973(%rip)
+# DISASM-NEXT: jmp   -128 <foo>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmp   -134 <foo>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmp   -139 <hid>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmp   -145 <hid>
+# DISASM-NEXT: nop
+# DISASM-NEXT: jmpq  *3943(%rip)
+# DISASM-NEXT: jmpq  *3937(%rip)
+
+.text
+.globl foo
+.type foo, @function
+foo:
+ nop
+
+.globl hid
+.hidden hid
+.type hid, @function
+hid:
+ nop
+
+.text
+.type ifunc STT_GNU_IFUNC
+.globl ifunc
+.type ifunc, @function
+ifunc:
+ ret
+
+.globl _start
+.type _start, @function
+_start:
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq foo@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq hid@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+ movq ifunc@GOTPCREL(%rip), %rax
+
+ call *foo@GOTPCREL(%rip)
+ call *foo@GOTPCREL(%rip)
+ call *hid@GOTPCREL(%rip)
+ call *hid@GOTPCREL(%rip)
+ call *ifunc@GOTPCREL(%rip)
+ call *ifunc@GOTPCREL(%rip)
+ jmp *foo@GOTPCREL(%rip)
+ jmp *foo@GOTPCREL(%rip)
+ jmp *hid@GOTPCREL(%rip)
+ jmp *hid@GOTPCREL(%rip)
+ jmp *ifunc@GOTPCREL(%rip)
+ jmp *ifunc@GOTPCREL(%rip)
diff --git a/test/ELF/gotpcrelx.s b/test/ELF/gotpcrelx.s
new file mode 100644 (file)
index 0000000..95dbf66
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -filetype=obj -relax-relocations -triple x86_64-pc-linux-gnu \
+// RUN: %s -o %t.o
+// RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=RELS %s
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -r %t.so | FileCheck %s
+
+movq foo@GOTPCREL(%rip), %rax
+movq bar@GOTPCREL(%rip), %rax
+
+// RELS: Relocations [
+// RELS-NEXT:   Section ({{.*}}) .rela.text {
+// RELS-NEXT:     R_X86_64_REX_GOTPCRELX foo 0xFFFFFFFFFFFFFFFC
+// RELS-NEXT:     R_X86_64_REX_GOTPCRELX bar 0xFFFFFFFFFFFFFFFC
+// RELS-NEXT:   }
+// RELS-NEXT: ]
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2090
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2098 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT:     0x2090 R_X86_64_GLOB_DAT foo 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/hidden-vis-shared.s b/test/ELF/hidden-vis-shared.s
new file mode 100644 (file)
index 0000000..f3fa206
--- /dev/null
@@ -0,0 +1,18 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+// RUN: ld.lld %t2.so %t.o -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+callq   bar
+.hidden bar
+.weak   bar
diff --git a/test/ELF/i386-got-and-copy.s b/test/ELF/i386-got-and-copy.s
new file mode 100644 (file)
index 0000000..f5b0b8e
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+
+# If there are two relocations such that the first one requires
+# dynamic COPY relocation, the second one requires GOT entry
+# creation, linker should create both - dynamic relocation
+# and GOT entry.
+
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux \
+# RUN:         %S/Inputs/copy-in-shared.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r %t.exe | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (4) .rel.dyn {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_386_COPY foo
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .global _start
+_start:
+  movl $foo, (%esp)     # R_386_32 - requires R_386_COPY relocation
+  movl foo@GOT, %eax    # R_386_GOT32 - requires GOT entry
diff --git a/test/ELF/i386-gotoff-shared.s b/test/ELF/i386-gotoff-shared.s
new file mode 100644 (file)
index 0000000..01242ad
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+// RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s
+
+bar:
+        movl    bar@GOTOFF(%ebx), %eax
+        mov     bar@GOT, %eax
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2050
+// CHECK-NEXT: Offset: 0x2050
+// CHECK-NEXT: Size: 4
+
+// 0x1000 - (0x2050 + 4) = -4180
+
+// DISASM:  1000: {{.*}} movl    -4180(%ebx), %eax
diff --git a/test/ELF/i386-gotpc-dynamic.s b/test/ELF/i386-gotpc-dynamic.s
new file mode 100644 (file)
index 0000000..da8a607
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.so -shared
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+# RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s
+
+# CHECK:       Section {
+# CHECK:        Index: 7
+# CHECK-NEXT:   Name: .got
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x2030
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+
+## 0x1000 + 4144 = 0x2030
+# DISASM: 1000: {{.*}} movl $4144, %eax
+
+.section .foo,"ax",@progbits
+foo:
+ movl $bar@got-., %eax # R_386_GOTPC
+
+.local bar
+bar:
diff --git a/test/ELF/i386-gotpc.s b/test/ELF/i386-gotpc.s
new file mode 100644 (file)
index 0000000..8222eff
--- /dev/null
@@ -0,0 +1,20 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+// RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s
+
+movl $_GLOBAL_OFFSET_TABLE_, %eax
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2030
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: .text:
+// DISASM-NEXT:    1000: {{.*}}         movl    $4144, %eax
+//                                              0x2030 - 0x1000 = 4144
diff --git a/test/ELF/i386-merge.s b/test/ELF/i386-merge.s
new file mode 100644 (file)
index 0000000..00c9549
--- /dev/null
@@ -0,0 +1,50 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+// CHECK:      Name: .mysec
+// CHECK-NEXT: Type:
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x114
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 42000000 |
+// CHECK-NEXT: )
+
+
+// CHECK:      Name: .data
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 14010000 |
+// CHECK-NEXT: )
+
+// The content of .data should be the address of .mysec. 14010000 is 0x114 in
+// little endian.
+
+        .data
+        .long .mysec+4
+
+        .section        .mysec,"aM",@progbits,4
+        .align  4
+        .long   0x42
+        .long   0x42
diff --git a/test/ELF/i386-pc16.test b/test/ELF/i386-pc16.test
new file mode 100644 (file)
index 0000000..14f8b50
--- /dev/null
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld -Ttext 0x0 %t.o -o %t.exe
+# RUN: llvm-objdump -s -section=.text %t.exe 2>&1 | FileCheck %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT:  0000 45231111 41231111
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_386
+Sections:
+  - Type:            SHT_PROGBITS
+    Name:            .text
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x04
+    Content:         "1111111111111111"
+  - Type:            SHT_REL
+    Name:            .rel.text
+    Link:            .symtab
+    Info:            .text
+    AddressAlign:    0x04
+    Relocations:
+      - Offset:          0
+        Symbol:          _start
+        Type:            R_386_16
+      - Offset:          4
+        Symbol:          _start
+        Type:            R_386_PC16
+Symbols:
+  Global:
+    - Name:     _start
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0x1234
+      Size:     4
diff --git a/test/ELF/i386-pc8-pc16-addend.s b/test/ELF/i386-pc8-pc16-addend.s
new file mode 100644 (file)
index 0000000..9d6424d
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux-gnu %s -o %t1.o
+
+# RUN: ld.lld %t1.o -o %t.out
+# RUN: llvm-objdump -s -t %t.out | FileCheck %s
+# CHECK:      Contents of section .text:
+# CHECK-NEXT:  11000 020000 
+## 0x11003 - 0x11000 + addend(-1) = 0x02
+## 0x11003 - 0x11001 + addend(-2) = 0x0000
+# CHECK: SYMBOL TABLE:
+# CHECK: 00011003 .und
+
+.byte  und-.-1
+.short und-.-2
+
+.section .und, "ax"
+und:
diff --git a/test/ELF/i386-pc8.s b/test/ELF/i386-pc8.s
new file mode 100644 (file)
index 0000000..65cbd21
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux-gnu %s -o %t1.o
+# RUN: ld.lld -Ttext 0x0 %t1.o -o %t.out
+# RUN: llvm-objdump -s -section=.text %t.out | FileCheck %s
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT:  0000 15253748
+
+.byte und-.+0x11
+.byte und-.+0x22
+.byte und+0x33
+.byte und+0x44
+
+.section .und, "ax"
+und:
diff --git a/test/ELF/i386-relative.s b/test/ELF/i386-relative.s
new file mode 100644 (file)
index 0000000..d814b5b
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -r %t.so | FileCheck %s
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
+// CHECK-NEXT:     R_386_RELATIVE - 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .data
+foo:
+        .long foo
diff --git a/test/ELF/i386-relax-reloc.s b/test/ELF/i386-relax-reloc.s
new file mode 100644 (file)
index 0000000..a7fdc40
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o -relax-relocations
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+foo:
+        movl bar@GOT(%ebx), %eax
+        movl bar+8@GOT(%ebx), %eax
+
+// CHECK: foo:
+// CHECK-NEXT: movl    -4(%ebx), %eax
+// CHECK-NEXT: movl    4(%ebx), %eax
diff --git a/test/ELF/i386-reloc-16.s b/test/ELF/i386-reloc-16.s
new file mode 100644 (file)
index 0000000..db9dc0b
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/x86-64-reloc-16.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+// RUN: ld.lld -shared %t %t1 -o %t3
+
+// CHECK:      Contents of section .text:
+// CHECK-NEXT:   200000 42
+
+// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
+// ERROR: relocation R_386_16 out of range
+
+.short foo
diff --git a/test/ELF/i386-reloc-8.s b/test/ELF/i386-reloc-8.s
new file mode 100644 (file)
index 0000000..b2e4426
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-reloc-8.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-reloc-8-error.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+// RUN: ld.lld -shared %t %t1 -o %t3
+
+// CHECK:      Contents of section .text:
+// CHECK-NEXT:   200000 42
+
+// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
+// ERROR: relocation R_386_8 out of range
+
+.byte foo
diff --git a/test/ELF/i386-reloc-large-addend.s b/test/ELF/i386-reloc-large-addend.s
new file mode 100644 (file)
index 0000000..5af5844
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj
+
+// RUN: echo ".global foo; foo = 0x1" > %t1.s
+// RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj
+
+// RUN: ld.lld -Ttext 0x7000 %t.o %t1.o -o %t
+// RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t | FileCheck %s
+
+// CHECK:        Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:     7000:       e9 fe 1f        jmp     8190
+//                            0x1 + 0x9000 - 0x7003 == 8190
+        .global _start
+_start:
+jmp foo + 0x9000
diff --git a/test/ELF/i386-reloc-range.s b/test/ELF/i386-reloc-range.s
new file mode 100644 (file)
index 0000000..4fb5325
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj
+
+// RUN: echo ".global foo; foo = 0x10202" > %t1.s
+// RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj
+// RUN: echo ".global foo; foo = 0x10203" > %t2.s
+// RUN: llvm-mc %t2.s -o %t2.o -triple i386-pc-linux -filetype=obj
+
+// RUN: ld.lld -Ttext 0x200 %t.o %t1.o -o %t1
+// RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t1 | FileCheck %s
+
+// CHECK:        Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:      200: {{.*}} jmp -1
+//              0x10202 - 0x203 == 0xffff
+
+// RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o %t2 2>&1 | FileCheck --check-prefix=ERR %s
+
+// ERR: {{.*}}:(.text+0x1): relocation R_386_PC16 out of range
+
+        .global _start
+_start:
+        jmp foo
diff --git a/test/ELF/i386-reloc8-reloc16-addend.s b/test/ELF/i386-reloc8-reloc16-addend.s
new file mode 100644 (file)
index 0000000..42a57ce
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux-gnu %s -o %t1.o
+
+# RUN: ld.lld -Ttext=0x0 %t1.o -o %t.out
+# RUN: llvm-objdump -s -t %t.out | FileCheck %s
+# CHECK:      Contents of section .text:
+# CHECK-NEXT:  0000 020100 
+## 0x3 + addend(-1) = 0x02
+## 0x3 + addend(-2) = 0x0100
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000003 .und
+
+.byte  und-1
+.short und-2
+
+.section .und, "ax"
+und:
diff --git a/test/ELF/i386-tls-got.s b/test/ELF/i386-tls-got.s
new file mode 100644 (file)
index 0000000..56be4a1
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-tls-got.s -o %t1.o
+# RUN: ld.lld %t1.o -o %t1.so -shared
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t2.o
+# RUN: ld.lld %t2.o %t1.so -o %t
+
+       addl    foobar@INDNTPOFF, %eax
diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s
new file mode 100644 (file)
index 0000000..f419eb4
--- /dev/null
@@ -0,0 +1,111 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld -shared %t.o %tso -o %t1
+// RUN: llvm-readobj -s -r -d %t1 | FileCheck --check-prefix=GOTRELSHARED %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASMSHARED %s
+
+// GOTRELSHARED:     Section {
+// GOTRELSHARED:      Index: 8
+// GOTRELSHARED:      Name: .got
+// GOTRELSHARED-NEXT:   Type: SHT_PROGBITS
+// GOTRELSHARED-NEXT:   Flags [
+// GOTRELSHARED-NEXT:     SHF_ALLOC
+// GOTRELSHARED-NEXT:     SHF_WRITE
+// GOTRELSHARED-NEXT:   ]
+// GOTRELSHARED-NEXT:   Address: 0x2058
+// GOTRELSHARED-NEXT:   Offset: 0x2058
+// GOTRELSHARED-NEXT:   Size: 16
+// GOTRELSHARED-NEXT:   Link: 0
+// GOTRELSHARED-NEXT:   Info: 0
+// GOTRELSHARED-NEXT:   AddressAlignment: 4
+// GOTRELSHARED-NEXT:   EntrySize: 0
+// GOTRELSHARED-NEXT: }
+// GOTRELSHARED:      Relocations [
+// GOTRELSHARED-NEXT:   Section ({{.*}}) .rel.dyn {
+// GOTRELSHARED-NEXT:     0x1002 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x100A R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x1013 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x101C R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x1024 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x102D R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x1036 R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x103F R_386_RELATIVE - 0x0
+// GOTRELSHARED-NEXT:     0x2058 R_386_TLS_TPOFF tlslocal0 0x0
+// GOTRELSHARED-NEXT:     0x205C R_386_TLS_TPOFF tlslocal1 0x0
+// GOTRELSHARED-NEXT:     0x2060 R_386_TLS_TPOFF tlsshared0 0x0
+// GOTRELSHARED-NEXT:     0x2064 R_386_TLS_TPOFF tlsshared1 0x0
+// GOTRELSHARED-NEXT:   }
+// GOTRELSHARED-NEXT: ]
+// GOTRELSHARED:      0x6FFFFFFA RELCOUNT             8
+
+// DISASMSHARED:       Disassembly of section test:
+// DISASMSHARED-NEXT:  _start:
+// (.got)[0] = 0x2058 = 8280
+// (.got)[1] = 0x205C = 8284
+// (.got)[2] = 0x2060 = 8288
+// (.got)[3] = 0x2064 = 8292
+// DISASMSHARED-NEXT:  1000: 8b 0d 58 20 00 00   movl  8280, %ecx
+// DISASMSHARED-NEXT:  1006: 65 8b 01  movl  %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  1009: a1 58 20 00 00  movl  8280, %eax
+// DISASMSHARED-NEXT:  100e: 65 8b 00  movl  %gs:(%eax), %eax
+// DISASMSHARED-NEXT:  1011: 03 0d 58 20 00 00   addl  8280, %ecx
+// DISASMSHARED-NEXT:  1017: 65 8b 01  movl  %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  101a: 8b 0d 5c 20 00 00   movl  8284, %ecx
+// DISASMSHARED-NEXT:  1020: 65 8b 01  movl  %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  1023: a1 5c 20 00 00  movl  8284, %eax
+// DISASMSHARED-NEXT:  1028: 65 8b 00  movl  %gs:(%eax), %eax
+// DISASMSHARED-NEXT:  102b: 03 0d 5c 20 00 00   addl  8284, %ecx
+// DISASMSHARED-NEXT:  1031: 65 8b 01  movl  %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  1034: 8b 0d 60 20 00 00   movl  8288, %ecx
+// DISASMSHARED-NEXT:  103a: 65 8b 01  movl  %gs:(%ecx), %eax
+// DISASMSHARED-NEXT:  103d: 03 0d 64 20 00 00   addl  8292, %ecx
+// DISASMSHARED-NEXT:  1043: 65 8b 01  movl  %gs:(%ecx), %eax
+
+.type tlslocal0,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal0
+.align 4
+tlslocal0:
+ .long 0
+ .size tlslocal0, 4
+
+.type tlslocal1,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal1
+.align 4
+tlslocal1:
+ .long 0
+ .size tlslocal1, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section test, "axw"
+.globl _start
+_start:
+movl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal0@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlsshared0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+addl tlsshared1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
diff --git a/test/ELF/icf-absolute.s b/test/ELF/icf-absolute.s
new file mode 100644 (file)
index 0000000..6013224
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-absolute.s -o %t2
+# RUN: ld.lld %t %t2 -o %t3 --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  .byte a1
+
+.section .text.f2, "ax"
+f2:
+  .byte a2
diff --git a/test/ELF/icf-comdat.s b/test/ELF/icf-comdat.s
new file mode 100644 (file)
index 0000000..28c0a58
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1,"ax"
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .text.f2,"axG",@progbits,foo,comdat
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/icf-i386.s b/test/ELF/icf-i386.s
new file mode 100644 (file)
index 0000000..292883e
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# This test is to make sure that we can handle implicit addends properly.
+
+# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK:     selected .text.f1
+# CHECK:       removed .text.f2
+# CHECK-NOT:   removed .text.f3
+
+.globl _start, f1, f2, f3
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  movl $42, 4(%edi)
+
+.section .text.f2, "ax"
+f2:
+  movl $42, 4(%edi)
+
+.section .text.f3, "ax"
+f3:
+  movl $42, 8(%edi)
diff --git a/test/ELF/icf-merge-sec.s b/test/ELF/icf-merge-sec.s
new file mode 100644 (file)
index 0000000..39f6a88
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge-sec.s -o %t2
+# RUN: ld.lld %t %t2 -o %t3 --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+.section .rodata.str,"aMS",@progbits,1
+.asciz "foo"
+.asciz "string 1"
+.asciz "string 2"
+
+.section .text.f1,"ax"
+.globl f1
+f1:
+.quad .rodata.str
diff --git a/test/ELF/icf-merge.s b/test/ELF/icf-merge.s
new file mode 100644 (file)
index 0000000..938b749
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge.s -o %t1
+# RUN: ld.lld %t %t1 -o %t1.out --icf=all --verbose | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge2.s -o %t2
+# RUN: ld.lld %t %t2 -o %t3.out --icf=all --verbose | FileCheck --check-prefix=NOMERGE %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge3.s -o %t3
+# RUN: ld.lld %t %t3 -o %t3.out --icf=all --verbose | FileCheck --check-prefix=NOMERGE %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+# NOMERGE-NOT: selected .text.f
+
+.section .rodata.str,"aMS",@progbits,1
+foo:
+.asciz "foo"
+.asciz "string 1"
+.asciz "string 2"
+
+.section .text.f1,"ax"
+.globl f1
+f1:
+lea foo+42(%rip), %rax
diff --git a/test/ELF/icf-non-mergeable.s b/test/ELF/icf-non-mergeable.s
new file mode 100644 (file)
index 0000000..378c7b3
--- /dev/null
@@ -0,0 +1,28 @@
+// REQUIRES: x86
+
+// This file contains two functions. They are themselves identical,
+// but because they have reloactions against different data section,
+// they are not mergeable.
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:    %p/Inputs/icf-non-mergeable.s -o %t2
+
+// RUN: ld.lld %t1 %t2 -o %t3 --icf=all --verbose | FileCheck %s
+
+// CHECK-NOT: selected .text.f1
+// CHECK-NOT:   removed .text.f2
+
+.globl _start, f1, f2, d1, d2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  movl $5, d1
+  ret
+
+.section .text.f2, "ax"
+f2:
+  movl $5, d2
+  ret
diff --git a/test/ELF/icf-none.s b/test/ELF/icf-none.s
new file mode 100644 (file)
index 0000000..671f208
--- /dev/null
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --icf=none --verbose | FileCheck %s
+
+# CHECK-NOT: selected .text.f1
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .text.f2, "ax"
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/icf1.s b/test/ELF/icf1.s
new file mode 100644 (file)
index 0000000..bb06007
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .text.f2, "ax"
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/icf2.s b/test/ELF/icf2.s
new file mode 100644 (file)
index 0000000..be59511
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/icf2.s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $60, %rdi
+  call f2
diff --git a/test/ELF/icf3.s b/test/ELF/icf3.s
new file mode 100644 (file)
index 0000000..9f39ff6
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/icf2.s -o %t2
+# RUN: ld.lld %t1 %t2 -o %t --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+# This section is not mergeable because the content is different from f2.
+.section .text.f1, "ax"
+f1:
+  mov $60, %rdi
+  call f2
+  mov $0, %rax
diff --git a/test/ELF/icf4.s b/test/ELF/icf4.s
new file mode 100644 (file)
index 0000000..08830c8
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $1, %rax
+
+.section .text.f2, "ax"
+f2:
+  mov $0, %rax
diff --git a/test/ELF/icf5.s b/test/ELF/icf5.s
new file mode 100644 (file)
index 0000000..952fe36
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+f1:
+  mov $0, %rax
+
+.section .text.f2, "awx"
+f2:
+  mov $0, %rax
diff --git a/test/ELF/icf6.s b/test/ELF/icf6.s
new file mode 100644 (file)
index 0000000..ecb62fe
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: Selected .text.f1
+# CHECK-NOT: Selected .text.f2
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .init, "ax"
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .fini, "ax"
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/icf7.s b/test/ELF/icf7.s
new file mode 100644 (file)
index 0000000..8504ca2
--- /dev/null
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+# RUN: llvm-objdump -t %t2 | FileCheck -check-prefix=ALIGN %s
+
+# CHECK: selected .text.f1
+# CHECK:   removed .text.f2
+
+# ALIGN: 0000000000201000 .text 00000000 _start
+# ALIGN: 0000000000201100 .text 00000000 f1
+
+.globl _start, f1, f2
+_start:
+  ret
+
+.section .text.f1, "ax"
+  .align 1
+f1:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
+
+.section .text.f2, "ax"
+  .align 256
+f2:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/icf8.s b/test/ELF/icf8.s
new file mode 100644 (file)
index 0000000..51163ea
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.so --icf=all -shared
+# RUN: llvm-objdump -t %t.so | FileCheck %s
+
+# CHECK: zed
+
+        .section        .foo,"ax",@progbits
+        nop
+
+        .section        .bar,"ax",@progbits
+zed:
+        nop
diff --git a/test/ELF/icf9.s b/test/ELF/icf9.s
new file mode 100644 (file)
index 0000000..c5a5329
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+### Make sure that we do not merge data.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s
+
+# CHECK-NOT: selected .data.d1
+# CHECK-NOT: selected .data.d2
+
+.globl _start, d1, d2
+_start:
+  ret
+
+.section .data.f1, "a"
+d1:
+  .byte 1
+
+.section .data.f2, "a"
+d2:
+  .byte 1
diff --git a/test/ELF/image-base.s b/test/ELF/image-base.s
new file mode 100644 (file)
index 0000000..a6d1607
--- /dev/null
@@ -0,0 +1,64 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -image-base=0x1000000 %t -o %t1
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+
+# RUN: ld.lld -image-base=0x1000 -z max-page-size=0x2000 %t -o %t1 2>&1 | FileCheck --check-prefix=WARN %s
+# WARN: warning: -image-base: address isn't multiple of page size: 0x1000
+
+
+.global _start
+_start:
+  nop
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x1000040
+# CHECK-NEXT:     PhysicalAddress: 0x1000040
+# CHECK-NEXT:     FileSize: 224
+# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x1000000
+# CHECK-NEXT:     PhysicalAddress: 0x1000000
+# CHECK-NEXT:     FileSize: 288
+# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD (0x1)
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x1001000
+# CHECK-NEXT:     PhysicalAddress: 0x1001000
+# CHECK-NEXT:     FileSize: 1
+# CHECK-NEXT:     MemSize: 1
+# CHECK-NEXT:     Flags [ (0x5)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK (0x6474E551)
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [ (0x6)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_W (0x2)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
diff --git a/test/ELF/incompatible-ar-first.s b/test/ELF/incompatible-ar-first.s
new file mode 100644 (file)
index 0000000..e076561
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive.s -o %ta.o
+// RUN: llvm-ar rc %t.a %ta.o
+// RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %tb.o
+// RUN: not ld.lld %t.a %tb.o 2>&1 | FileCheck %s
+
+// We used to crash when
+// * The first object seen by the symbol table is from an archive.
+// * -m was not used.
+// CHECK: .a({{.*}}a.o) is incompatible with {{.*}}b.o
+
+// REQUIRES: x86
diff --git a/test/ELF/incompatible-section-flags.s b/test/ELF/incompatible-section-flags.s
new file mode 100644 (file)
index 0000000..25d9994
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s
+
+// CHECK:      error: incompatible section flags for .foo
+// CHECK-NEXT: >>> {{.*}}incompatible-section-flags.s.tmp.o:(.foo): 0x3
+// CHECK-NEXT: >>> output section .foo: 0x403
+
+// CHECK:      error: incompatible section flags for .bar
+// CHECK-NEXT: >>> {{.*}}incompatible-section-flags.s.tmp.o:(.bar): 0x403
+// CHECK-NEXT: >>> output section .bar: 0x3
+
+.section .foo, "awT", @progbits, unique, 1
+.quad 0
+
+.section .foo, "aw", @progbits, unique, 2
+.quad 0
+
+
+.section .bar, "aw", @progbits, unique, 3
+.quad 0
+
+.section .bar, "awT", @progbits, unique, 4
+.quad 0
diff --git a/test/ELF/incompatible-section-types2.s b/test/ELF/incompatible-section-types2.s
new file mode 100644 (file)
index 0000000..146e680
--- /dev/null
@@ -0,0 +1,9 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+// CHECK:      error: section type mismatch for .shstrtab
+// CHECK-NEXT: >>> <internal>:(.shstrtab): SHT_STRTAB
+// CHECK-NEXT: >>> output section .shstrtab: Unknown
+
+.section .shstrtab,"",@12345
+.short 20
diff --git a/test/ELF/incompatible.s b/test/ELF/incompatible.s
new file mode 100644 (file)
index 0000000..ce84606
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %ta.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tb.o
+// RUN: ld.lld -shared %tb.o -o %ti686.so
+// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tc.o
+
+// RUN: not ld.lld %ta.o %tb.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=A-AND-B %s
+// A-AND-B: b.o is incompatible with {{.*}}a.o
+
+// RUN: not ld.lld %tb.o %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=B-AND-C %s
+// B-AND-C: c.o is incompatible with {{.*}}b.o
+
+// RUN: not ld.lld %ta.o %ti686.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=A-AND-SO %s
+// A-AND-SO: i686.so is incompatible with {{.*}}a.o
+
+// RUN: not ld.lld %tc.o %ti686.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=C-AND-SO %s
+// C-AND-SO: i686.so is incompatible with {{.*}}c.o
+
+// RUN: not ld.lld %ti686.so %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=SO-AND-C %s
+// SO-AND-C: c.o is incompatible with {{.*}}i686.so
+
+// RUN: not ld.lld -m elf64ppc %ta.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=A-ONLY %s
+// A-ONLY: a.o is incompatible with elf64ppc
+
+// RUN: not ld.lld -m elf64ppc %tb.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=B-ONLY %s
+// B-ONLY: b.o is incompatible with elf64ppc
+
+// RUN: not ld.lld -m elf64ppc %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=C-ONLY %s
+// C-ONLY: c.o is incompatible with elf64ppc
+
+// RUN: not ld.lld -m elf_i386 %tc.o %ti686.so -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=C-AND-SO-I386 %s
+// C-AND-SO-I386: c.o is incompatible with elf_i386
+
+// RUN: not ld.lld -m elf_i386 %ti686.so %tc.o -o %t 2>&1 | \
+// RUN:   FileCheck --check-prefix=SO-AND-C-I386 %s
+// SO-AND-C-I386: c.o is incompatible with elf_i386
+
+
+// We used to fail to identify this incompatibility and crash trying to
+// read a 64 bit file as a 32 bit one.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive2.s -o %ta.o
+// RUN: llvm-ar rc %t.a %ta.o
+// RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %tb.o
+// RUN: not ld.lld %t.a %tb.o 2>&1 | FileCheck --check-prefix=ARCHIVE %s
+// ARCHIVE: .a({{.*}}a.o) is incompatible with {{.*}}b.o
+.global _start
+_start:
+.data
+        .long foo
+
+// REQUIRES: x86,aarch64
diff --git a/test/ELF/init-fini-progbits.s b/test/ELF/init-fini-progbits.s
new file mode 100644 (file)
index 0000000..a874944
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t.exe
+// RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+// CHECK:      Name: .init_array
+// CHECK-NEXT: Type: SHT_INIT_ARRAY
+// CHECK:      Name: .fini_array
+// CHECK-NEXT: Type: SHT_FINI_ARRAY
+
+.globl _start
+_start:
+  nop
+
+.section .init_array.100, "aw", @progbits
+  .byte 0
+.section .fini_array.100, "aw", @progbits
+  .byte 0
diff --git a/test/ELF/init-fini.s b/test/ELF/init-fini.s
new file mode 100644 (file)
index 0000000..37d8b01
--- /dev/null
@@ -0,0 +1,54 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+// Should use "_init" and "_fini" by default when fills dynamic table
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=BYDEF %s
+// BYDEF: INIT 0x11010
+// BYDEF: FINI 0x11020
+
+// -init and -fini override symbols to use
+// RUN: ld.lld -shared %t -o %t2 -init _foo -fini _bar
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s
+// OVR: INIT 0x11030
+// OVR: FINI 0x11040
+
+// Check aliases as well
+// RUN: ld.lld -shared %t -o %t2 -init=_foo -fini=_bar
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s
+
+// Don't add an entry for undef. The freebsd dynamic linker doesn't
+// check if the value is null. If it is, it will just call the
+// load address.
+// RUN: ld.lld -shared %t -o %t2 -init=_undef -fini=_undef
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=UNDEF %s
+// UNDEF-NOT: INIT
+// UNDEF-NOT: FINI
+
+// Don't add an entry for shared. For the same reason as undef.
+// RUN: ld.lld -shared %t -o %t.so
+// RUN: echo > %t.s
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t2.o
+// RUN: ld.lld -shared %t2.o %t.so -o %t2
+// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=SHARED %s
+// SHARED-NOT: INIT
+// SHARED-NOT: FINI
+
+// Should not add new entries to the symbol table
+// and should not require given symbols to be resolved
+// RUN: ld.lld -shared %t -o %t2 -init=_unknown -fini=_unknown
+// RUN: llvm-readobj -symbols -dynamic-table %t2 | FileCheck --check-prefix=NOENTRY %s
+// NOENTRY: Symbols [
+// NOENTRY-NOT: Name: _unknown
+// NOENTRY: ]
+// NOENTRY: DynamicSection [
+// NOENTRY-NOT: INIT
+// NOENTRY-NOT: FINI
+// NOENTRY: ]
+
+.global _start,_init,_fini,_foo,_bar,_undef
+_start:
+_init = 0x11010
+_fini = 0x11020
+_foo  = 0x11030
+_bar  = 0x11040
diff --git a/test/ELF/init_fini_priority.s b/test/ELF/init_fini_priority.s
new file mode 100644 (file)
index 0000000..84e5dc3
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t.exe
+// RUN: llvm-objdump -s %t.exe | FileCheck %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  nop
+
+.section .init_array, "aw", @init_array
+  .align 8
+  .byte 1
+.section .init_array.100, "aw", @init_array
+  .long 2
+.section .init_array.5, "aw", @init_array
+  .byte 3
+.section .init_array, "aw", @init_array
+  .byte 4
+.section .init_array, "aw", @init_array
+  .byte 5
+
+.section .fini_array, "aw", @fini_array
+  .align 8
+  .byte 0x11
+.section .fini_array.100, "aw", @fini_array
+  .long 0x12
+.section .fini_array.5, "aw", @fini_array
+  .byte 0x13
+.section .fini_array, "aw", @fini_array
+  .byte 0x14
+.section .fini_array, "aw", @fini_array
+  .byte 0x15
+
+// CHECK:      Contents of section .init_array:
+// CHECK-NEXT: 03020000 00000000 010405
+// CHECK:      Contents of section .fini_array:
+// CHECK-NEXT: 13120000 00000000 111415
diff --git a/test/ELF/invalid-cie-length.s b/test/ELF/invalid-cie-length.s
new file mode 100644 (file)
index 0000000..c6da95e
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+.section .eh_frame
+.byte 0
+
+// CHECK:      error: corrupted .eh_frame: CIE/FDE too small
+// CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x0)
diff --git a/test/ELF/invalid-cie-length2.s b/test/ELF/invalid-cie-length2.s
new file mode 100644 (file)
index 0000000..9140280
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+.section .eh_frame
+.long 42
+
+// CHECK:      error: corrupted .eh_frame: CIE/FDE ends past the end of the section
+// CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x0)
diff --git a/test/ELF/invalid-cie-length3.s b/test/ELF/invalid-cie-length3.s
new file mode 100644 (file)
index 0000000..fcbfa7f
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+.section .eh_frame
+.long 0xFFFFFFFC
+
+// CHECK:      error: corrupted .eh_frame: CIE/FDE ends past the end of the section
+// CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x0)
+
diff --git a/test/ELF/invalid-cie-length4.s b/test/ELF/invalid-cie-length4.s
new file mode 100644 (file)
index 0000000..04f8eb2
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+.section .eh_frame
+.long 0xFFFFFFFF
+.byte 0
+
+// CHECK:      error: corrupted .eh_frame: CIE/FDE too large
+// CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x0)
diff --git a/test/ELF/invalid-cie-length5.s b/test/ELF/invalid-cie-length5.s
new file mode 100644 (file)
index 0000000..bfa35ed
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .long 0xFFFFFFFF
+ .quad 0xFFFFFFFFFFFFFFF4
+
+// CHECK: CIE/FDE too large
diff --git a/test/ELF/invalid-cie-reference.s b/test/ELF/invalid-cie-reference.s
new file mode 100644 (file)
index 0000000..fba2467
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+        .section .eh_frame
+        .long 0x14
+        .long 0x0
+        .byte 0x01
+        .byte 0x7a
+        .byte 0x52
+        .byte 0x00
+        .byte 0x01
+        .byte 0x78
+        .byte 0x10
+        .byte 0x01
+        .byte 0x1b
+        .byte 0x0c
+        .byte 0x07
+        .byte 0x08
+        .byte 0x90
+        .byte 0x01
+        .short 0x0
+
+        .long 0x14
+        .long 0x1b
+        .long .text
+        .long 0x0
+        .long 0x0
+        .long 0x0
+
+// CHECK: invalid CIE reference
diff --git a/test/ELF/invalid-dynamic-list.test b/test/ELF/invalid-dynamic-list.test
new file mode 100644 (file)
index 0000000..f560cee
--- /dev/null
@@ -0,0 +1,37 @@
+## Different "echo" commands on Windows interpret quoted strings and
+## wildcards in similar but different way (On Windows, ARGV tokenization
+## and wildcard expansion are not done by the shell but by each command.)
+## Because of that reason, this test fails on some Windows environment.
+## We can't write quoted strings that are interpreted the same way
+## by all echo commands. So, we don't want to run this on Windows.
+
+# REQUIRES: shell
+
+# RUN: mkdir -p %t.dir
+
+# RUN: echo foobar > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: {{.*}}:1: { expected, but got foobar
+
+# RUN: echo "{ foobar;" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: {{.*}}:1: unexpected EOF
+
+## Missing ';' before '}'
+# RUN: echo "{ foobar }" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: {{.*}}:1: ; expected, but got }
+
+## Missing final ';'
+# RUN: echo "{ foobar; }" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: {{.*}}:1: unexpected EOF
+
+## Missing \" in foobar definition
+# RUN echo "{ \"foobar; };" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: {{.*}}:1: unexpected EOF
+
+# RUN: echo "{ extern \"BOGUS\" { test }; };" > %t1
+# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: {{.*}}:1: Unknown language
diff --git a/test/ELF/invalid-fde-rel.s b/test/ELF/invalid-fde-rel.s
new file mode 100644 (file)
index 0000000..f43b9da
--- /dev/null
@@ -0,0 +1,36 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -h %t2 | FileCheck %s
+
+// This resembles what gold -r produces when it discards the section
+// the fde points to.
+
+        .section .eh_frame
+        .long 0x14
+        .long 0x0
+        .byte 0x01
+        .byte 0x7a
+        .byte 0x52
+        .byte 0x00
+        .byte 0x01
+        .byte 0x78
+        .byte 0x10
+        .byte 0x01
+        .byte 0x1b
+        .byte 0x0c
+        .byte 0x07
+        .byte 0x08
+        .byte 0x90
+        .byte 0x01
+        .short 0x0
+
+        .long 0x14
+        .long 0x1c
+        .long 0x0
+        .long 0x0
+        .long 0x0
+        .long 0x0
+
+// CHECK:  1 .eh_frame     00000018
diff --git a/test/ELF/invalid-linkerscript.test b/test/ELF/invalid-linkerscript.test
new file mode 100644 (file)
index 0000000..280686e
--- /dev/null
@@ -0,0 +1,54 @@
+## Different "echo" commands on Windows interpret quoted strings and
+## wildcards in similar but different way (On Windows, ARGV tokenization
+## and wildcard expansion are not done by the shell but by each command.)
+## Because of that reason, this test fails on some Windows environment.
+## We can't write quoted strings that are interpreted the same way
+## by all echo commands. So, we don't want to run this on Windows.
+
+# REQUIRES: shell
+
+# RUN: mkdir -p %t.dir
+
+## Note that we are using "cannot open no-such-file: " as a marker that the
+## linker keep going when it found an error. That specific error message is not
+## related to the linker script tests.
+
+# RUN: echo foobar > %t1
+# RUN: not ld.lld %t1 no-such-file 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: unexpected EOF
+# ERR1: cannot open no-such-file:
+
+# RUN: echo "foo \"bar" > %t2
+# RUN: not ld.lld %t2 no-such-file 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: unclosed quote
+# ERR2: cannot open no-such-file:
+
+# RUN: echo "/*" > %t3
+# RUN: not ld.lld %t3 no-such-file 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: unclosed comment
+# ERR3: cannot open no-such-file:
+
+# RUN: echo "EXTERN (" > %t4
+# RUN: not ld.lld %t4 no-such-file 2>&1 | FileCheck -check-prefix=ERR4 %s
+# ERR4: unexpected EOF
+# ERR4: cannot open no-such-file:
+
+# RUN: echo "EXTERN (" > %t5
+# RUN: not ld.lld %t5 no-such-file 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: unexpected EOF
+# ERR5: cannot open no-such-file:
+
+# RUN: echo "EXTERN xyz" > %t6
+# RUN: not ld.lld %t6 no-such-file 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: ( expected, but got xyz
+# ERR6: cannot open no-such-file:
+
+# RUN: echo "INCLUDE /no/such/file" > %t7
+# RUN: not ld.lld %t7 no-such-file 2>&1 | FileCheck -check-prefix=ERR7 %s
+# ERR7: cannot open /no/such/file
+# ERR7: cannot open no-such-file:
+
+# RUN: echo "OUTPUT_FORMAT(x y z)" > %t8
+# RUN: not ld.lld %t8 no-such-file 2>&1 | FileCheck -check-prefix=ERR8 %s
+# ERR8: , expected, but got y
+# ERR8: cannot open no-such-file:
diff --git a/test/ELF/invalid-relocations.test b/test/ELF/invalid-relocations.test
new file mode 100644 (file)
index 0000000..cfeb44b
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: yaml2obj %s -o %t
+# RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Type:            SHT_PROGBITS
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Info:            12 # Invalid index
+    Relocations:
+      - Offset:          0x0000000000000001
+        Symbol:          lulz
+        Type:            R_X86_64_PC32
+Symbols:
+  Global:
+    - Name:            lulz
+
+# CHECK: invalid relocated section index
diff --git a/test/ELF/invalid-z.s b/test/ELF/invalid-z.s
new file mode 100644 (file)
index 0000000..a5343c9
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t -z max-page-size 2>&1 | FileCheck %s
+# CHECK: invalid max-page-size
+# CHECK-NOT: error
+
+.global _start
+_start:
+  nop
diff --git a/test/ELF/invalid/Inputs/binding.elf b/test/ELF/invalid/Inputs/binding.elf
new file mode 100644 (file)
index 0000000..61b5af9
Binary files /dev/null and b/test/ELF/invalid/Inputs/binding.elf differ
diff --git a/test/ELF/invalid/Inputs/broken-relaxation-x64.elf b/test/ELF/invalid/Inputs/broken-relaxation-x64.elf
new file mode 100644 (file)
index 0000000..01a6af9
Binary files /dev/null and b/test/ELF/invalid/Inputs/broken-relaxation-x64.elf differ
diff --git a/test/ELF/invalid/Inputs/cie-version2.elf b/test/ELF/invalid/Inputs/cie-version2.elf
new file mode 100644 (file)
index 0000000..87f8a5b
Binary files /dev/null and b/test/ELF/invalid/Inputs/cie-version2.elf differ
diff --git a/test/ELF/invalid/Inputs/common-symbol-alignment.elf b/test/ELF/invalid/Inputs/common-symbol-alignment.elf
new file mode 100644 (file)
index 0000000..9e7823b
Binary files /dev/null and b/test/ELF/invalid/Inputs/common-symbol-alignment.elf differ
diff --git a/test/ELF/invalid/Inputs/common-symbol-alignment2.elf b/test/ELF/invalid/Inputs/common-symbol-alignment2.elf
new file mode 100644 (file)
index 0000000..21c2457
Binary files /dev/null and b/test/ELF/invalid/Inputs/common-symbol-alignment2.elf differ
diff --git a/test/ELF/invalid/Inputs/data-encoding.a b/test/ELF/invalid/Inputs/data-encoding.a
new file mode 100644 (file)
index 0000000..ff2b373
Binary files /dev/null and b/test/ELF/invalid/Inputs/data-encoding.a differ
diff --git a/test/ELF/invalid/Inputs/dynamic-section-sh_size.elf b/test/ELF/invalid/Inputs/dynamic-section-sh_size.elf
new file mode 100644 (file)
index 0000000..ea35dba
Binary files /dev/null and b/test/ELF/invalid/Inputs/dynamic-section-sh_size.elf differ
diff --git a/test/ELF/invalid/Inputs/file-class.a b/test/ELF/invalid/Inputs/file-class.a
new file mode 100644 (file)
index 0000000..f0ce607
Binary files /dev/null and b/test/ELF/invalid/Inputs/file-class.a differ
diff --git a/test/ELF/invalid/Inputs/invalid-e_shnum.elf b/test/ELF/invalid/Inputs/invalid-e_shnum.elf
new file mode 100644 (file)
index 0000000..0b46fbd
Binary files /dev/null and b/test/ELF/invalid/Inputs/invalid-e_shnum.elf differ
diff --git a/test/ELF/invalid/Inputs/mips-invalid-options-descriptor.elf b/test/ELF/invalid/Inputs/mips-invalid-options-descriptor.elf
new file mode 100644 (file)
index 0000000..85feeeb
Binary files /dev/null and b/test/ELF/invalid/Inputs/mips-invalid-options-descriptor.elf differ
diff --git a/test/ELF/invalid/Inputs/multiple-eh-relocs.elf b/test/ELF/invalid/Inputs/multiple-eh-relocs.elf
new file mode 100644 (file)
index 0000000..6291459
Binary files /dev/null and b/test/ELF/invalid/Inputs/multiple-eh-relocs.elf differ
diff --git a/test/ELF/invalid/Inputs/section-alignment-notpow2.elf b/test/ELF/invalid/Inputs/section-alignment-notpow2.elf
new file mode 100644 (file)
index 0000000..59d4de7
Binary files /dev/null and b/test/ELF/invalid/Inputs/section-alignment-notpow2.elf differ
diff --git a/test/ELF/invalid/Inputs/section-index.elf b/test/ELF/invalid/Inputs/section-index.elf
new file mode 100644 (file)
index 0000000..ec5adcf
Binary files /dev/null and b/test/ELF/invalid/Inputs/section-index.elf differ
diff --git a/test/ELF/invalid/Inputs/section-index2.elf b/test/ELF/invalid/Inputs/section-index2.elf
new file mode 100644 (file)
index 0000000..5d84288
Binary files /dev/null and b/test/ELF/invalid/Inputs/section-index2.elf differ
diff --git a/test/ELF/invalid/Inputs/shentsize-zero.elf b/test/ELF/invalid/Inputs/shentsize-zero.elf
new file mode 100644 (file)
index 0000000..5fa7df2
Binary files /dev/null and b/test/ELF/invalid/Inputs/shentsize-zero.elf differ
diff --git a/test/ELF/invalid/Inputs/sht-group.elf b/test/ELF/invalid/Inputs/sht-group.elf
new file mode 100644 (file)
index 0000000..5cb0336
Binary files /dev/null and b/test/ELF/invalid/Inputs/sht-group.elf differ
diff --git a/test/ELF/invalid/Inputs/symbol-index.elf b/test/ELF/invalid/Inputs/symbol-index.elf
new file mode 100644 (file)
index 0000000..f31ffbf
Binary files /dev/null and b/test/ELF/invalid/Inputs/symbol-index.elf differ
diff --git a/test/ELF/invalid/Inputs/symbol-name-offset.elf b/test/ELF/invalid/Inputs/symbol-name-offset.elf
new file mode 100644 (file)
index 0000000..8b8abde
Binary files /dev/null and b/test/ELF/invalid/Inputs/symbol-name-offset.elf differ
diff --git a/test/ELF/invalid/Inputs/symtab-sh_info.elf b/test/ELF/invalid/Inputs/symtab-sh_info.elf
new file mode 100644 (file)
index 0000000..aa63d58
Binary files /dev/null and b/test/ELF/invalid/Inputs/symtab-sh_info.elf differ
diff --git a/test/ELF/invalid/Inputs/symtab-sh_info2.elf b/test/ELF/invalid/Inputs/symtab-sh_info2.elf
new file mode 100644 (file)
index 0000000..4fea12c
Binary files /dev/null and b/test/ELF/invalid/Inputs/symtab-sh_info2.elf differ
diff --git a/test/ELF/invalid/Inputs/symtab-sh_info3.elf b/test/ELF/invalid/Inputs/symtab-sh_info3.elf
new file mode 100644 (file)
index 0000000..ca889fb
Binary files /dev/null and b/test/ELF/invalid/Inputs/symtab-sh_info3.elf differ
diff --git a/test/ELF/invalid/Inputs/tls-symbol.elf b/test/ELF/invalid/Inputs/tls-symbol.elf
new file mode 100644 (file)
index 0000000..78c7598
Binary files /dev/null and b/test/ELF/invalid/Inputs/tls-symbol.elf differ
diff --git a/test/ELF/invalid/Inputs/too-short.elf b/test/ELF/invalid/Inputs/too-short.elf
new file mode 100644 (file)
index 0000000..077f392
Binary files /dev/null and b/test/ELF/invalid/Inputs/too-short.elf differ
diff --git a/test/ELF/invalid/broken-relaxation-x64.test b/test/ELF/invalid/broken-relaxation-x64.test
new file mode 100644 (file)
index 0000000..10d4655
--- /dev/null
@@ -0,0 +1,46 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
+# ERR: R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only
+
+## YAML below contains 2 relocations of type R_X86_64_GOTTPOFF, and a .text
+## with fake content filled by 0xFF. That means instructions for relaxation are
+## "broken", so they does not match any known valid relaxations. We also generate
+## .tls section because we need it for correct proccessing of STT_TLS symbol.
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_FREEBSD
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Type:            SHT_PROGBITS
+    Name:            .text
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x04
+    Content:         "FFFFFFFFFFFFFFFF"
+  - Type:            SHT_PROGBITS
+    Name:            .tls
+    Flags:           [ SHF_ALLOC, SHF_TLS ]
+  - Type:            SHT_REL
+    Name:            .rel.text
+    Link:            .symtab
+    Info:            .text
+    AddressAlign:    0x04
+    Relocations:
+      - Offset:          4
+        Symbol:          foo
+        Type:            R_X86_64_GOTTPOFF
+      - Offset:          4
+        Symbol:          foo
+        Type:            R_X86_64_GOTTPOFF
+Symbols:
+  Global:
+    - Name:     foo
+      Type:     STT_TLS
+      Section:  .text
+      Value:    0x12345
+      Size:     4
diff --git a/test/ELF/invalid/common-symbol-alignment.s b/test/ELF/invalid/common-symbol-alignment.s
new file mode 100644 (file)
index 0000000..2a654b1
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+
+## common-symbol-alignment.elf contains common symbol with zero alignment.
+# RUN: not ld.lld %S/Inputs/common-symbol-alignment.elf \
+# RUN:   -o %t 2>&1 | FileCheck %s
+# CHECK: common symbol 'bar' has invalid alignment: 0
+
+## common-symbol-alignment2.elf contains common symbol alignment greater
+## than UINT32_MAX.
+# RUN: not ld.lld %S/Inputs/common-symbol-alignment2.elf \
+# RUN:   -o %t 2>&1 | FileCheck %s --check-prefix=BIG
+# BIG: common symbol 'bar' has invalid alignment: 271644049215
diff --git a/test/ELF/invalid/dynamic-section-size.s b/test/ELF/invalid/dynamic-section-size.s
new file mode 100644 (file)
index 0000000..323daba
--- /dev/null
@@ -0,0 +1,4 @@
+## dynamic-section-sh_size.elf has incorrect sh_size of dynamic section.
+# RUN: not ld.lld %p/Inputs/dynamic-section-sh_size.elf -o %t2 2>&1 | \
+# RUN:   FileCheck %s
+# CHECK: error: {{.*}}: invalid sh_entsize
diff --git a/test/ELF/invalid/eh-frame-hdr-no-out.s b/test/ELF/invalid/eh-frame-hdr-no-out.s
new file mode 100644 (file)
index 0000000..8379253
--- /dev/null
@@ -0,0 +1,6 @@
+// REQUIRES: x86
+// RUN: not ld.lld --eh-frame-hdr %p/Inputs/cie-version2.elf -o %t >& %t.log
+// RUN: FileCheck %s < %t.log
+
+// cie-version2.elf contains unsupported version of CIE = 2.
+// CHECK: FDE version 1 or 3 expected, but got 2
diff --git a/test/ELF/invalid/invalid-debug-relocations.test b/test/ELF/invalid/invalid-debug-relocations.test
new file mode 100644 (file)
index 0000000..75e41d1
--- /dev/null
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld -gdb-index %t.o -o %t.exe 2>&1 | FileCheck %s
+
+# CHECK:      error: {{.*}}.o: error parsing DWARF data:
+# CHECK-NEXT: >>> failed to compute relocation: Unknown, Invalid data was encountered while parsing the file
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_386
+Sections:
+  - Type:            SHT_PROGBITS
+    Name:            .text
+    Flags:           [ ]
+    AddressAlign:    0x04
+    Content:         "0000"
+  - Type:            SHT_PROGBITS
+    Name:            .debug_info
+    Flags:           [ ]
+    AddressAlign:    0x04
+    Content:         "0000"
+  - Type:            SHT_REL
+    Name:            .rel.debug_info
+    Link:            .symtab
+    Info:            .debug_info
+    Relocations:
+      - Offset:          0
+        Symbol:          _start
+        Type:            0xFF
+      - Offset:          4
+        Symbol:          _start
+        Type:            0xFF
+Symbols:
+  Global:
+    - Name:     _start
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0x0
diff --git a/test/ELF/invalid/invalid-e_shnum.s b/test/ELF/invalid/invalid-e_shnum.s
new file mode 100644 (file)
index 0000000..0c720ff
--- /dev/null
@@ -0,0 +1,3 @@
+## Spec says that "If a file has no section header table, e_shnum holds the value zero.", though
+## in this test case it holds non-zero and lld used to crash.
+# RUN: ld.lld %p/Inputs/invalid-e_shnum.elf -o %t2
diff --git a/test/ELF/invalid/invalid-elf.test b/test/ELF/invalid/invalid-elf.test
new file mode 100644 (file)
index 0000000..e03450e
--- /dev/null
@@ -0,0 +1,31 @@
+# RUN: llvm-mc %s -o %t -filetype=obj -triple x86_64-pc-linux
+
+# RUN: not ld.lld %t %p/Inputs/data-encoding.a -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-DATA-ENC %s
+# INVALID-DATA-ENC: test.o: invalid data encoding
+
+# RUN: not ld.lld %t %p/Inputs/file-class.a -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-FILE-CLASS %s
+# INVALID-FILE-CLASS: test.o: invalid file class
+
+# RUN: not ld.lld %p/Inputs/symtab-sh_info.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SYMTAB-SHINFO %s
+# INVALID-SYMTAB-SHINFO: invalid sh_info in symbol table
+
+# RUN: not ld.lld %p/Inputs/binding.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-BINDING %s
+# INVALID-BINDING: unexpected binding
+
+# RUN: not ld.lld %p/Inputs/section-index.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SECTION-INDEX-LLD %s
+# INVALID-SECTION-INDEX-LLD: invalid section index
+
+## section-index2.elf has local symbol with incorrect section index.
+# RUN: not ld.lld %p/Inputs/section-index2.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SECTION-INDEX-LLD %s
+
+# RUN: not ld.lld %p/Inputs/multiple-eh-relocs.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-EH-RELOCS %s
+# INVALID-EH-RELOCS: multiple relocation sections to one section are not supported
+
+.long foo
diff --git a/test/ELF/invalid/invalid-relocation-x64.test b/test/ELF/invalid/invalid-relocation-x64.test
new file mode 100644 (file)
index 0000000..9b8ebb5
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+# CHECK: {{.*}}.o: unknown relocation type: Unknown (152)
+# CHECK: {{.*}}.o: unknown relocation type: Unknown (153)
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_FREEBSD
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          ''
+        Type:            0x98
+      - Offset:          0x0000000000000000
+        Symbol:          ''
+        Type:            0x99
diff --git a/test/ELF/invalid/merge-invalid-size.s b/test/ELF/invalid/merge-invalid-size.s
new file mode 100644 (file)
index 0000000..1dbd7cf
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: SHF_MERGE section size must be a multiple of sh_entsize
+
+// Test that we accept a zero sh_entsize.
+// RUN: ld.lld %p/Inputs/shentsize-zero.elf -o %t2
+
+.section .foo,"aM",@progbits,4
+.short 42
diff --git a/test/ELF/invalid/mips-invalid-options-descriptor.s b/test/ELF/invalid/mips-invalid-options-descriptor.s
new file mode 100644 (file)
index 0000000..b23ecee
--- /dev/null
@@ -0,0 +1,5 @@
+## mips-invalid-options-descriptor.elf has option descriptor in
+## .MIPS.options with size of zero.
+# RUN: not ld.lld %p/Inputs/mips-invalid-options-descriptor.elf -o %t2 2>&1 | \
+# RUN:   FileCheck %s
+# CHECK: error: {{.*}}: invalid section offset
diff --git a/test/ELF/invalid/section-alignment.test b/test/ELF/invalid/section-alignment.test
new file mode 100644 (file)
index 0000000..48da122
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: yaml2obj %s -o %t
+# RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+
+## In current lld implementation, we do not accept sh_addralign
+## larger than UINT32_MAX.
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x1000000000000000
+    Content:         "00000000"
+
+# CHECK: section sh_addralign is too large
diff --git a/test/ELF/invalid/section-alignment2.s b/test/ELF/invalid/section-alignment2.s
new file mode 100644 (file)
index 0000000..aaef9f8
--- /dev/null
@@ -0,0 +1,5 @@
+## section-alignment-notpow2.elf has section alignment
+## 0xFFFFFFFF which is not a power of 2.
+# RUN: not ld.lld %p/Inputs/section-alignment-notpow2.elf -o %t2 2>&1 | \
+# RUN:   FileCheck %s
+# CHECK: section sh_addralign is not a power of 2
diff --git a/test/ELF/invalid/sht-group.s b/test/ELF/invalid/sht-group.s
new file mode 100644 (file)
index 0000000..f28035f
--- /dev/null
@@ -0,0 +1,3 @@
+## sht-group.elf contains SHT_GROUP section with invalid sh_info.
+# RUN: not ld.lld %p/Inputs/sht-group.elf -o %t2 2>&1 | FileCheck %s
+# CHECK: invalid symbol index
diff --git a/test/ELF/invalid/symbol-index.s b/test/ELF/invalid/symbol-index.s
new file mode 100644 (file)
index 0000000..4ad1d6c
--- /dev/null
@@ -0,0 +1,10 @@
+## symbol-index.elf has incorrect type of .symtab section.
+## There is no symbol bodies because of that and any symbol index becomes incorrect.
+## Section Headers:
+##   [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
+##   [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
+## ...
+##   [ 4] .symtab           RELA            0000000000000000 000048 000030 18      1   2  8
+# RUN: not ld.lld %p/Inputs/symbol-index.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SYMBOL-INDEX %s
+# INVALID-SYMBOL-INDEX: invalid symbol index
diff --git a/test/ELF/invalid/symbol-name.s b/test/ELF/invalid/symbol-name.s
new file mode 100644 (file)
index 0000000..8daee1a
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+
+## symbol-name-offset.elf contains symbol with invalid (too large)
+## st_name value.
+# RUN: not ld.lld %S/Inputs/symbol-name-offset.elf \
+# RUN:   -o %t 2>&1 | FileCheck %s
+# CHECK: invalid symbol name offset
diff --git a/test/ELF/invalid/symtab-sh-info.s b/test/ELF/invalid/symtab-sh-info.s
new file mode 100644 (file)
index 0000000..3522ae5
--- /dev/null
@@ -0,0 +1,9 @@
+## sh_info contains zero value. First entry in a symbol table is always completely zeroed,
+## so sh_info should be at least 1 in a valid ELF.
+# RUN: not ld.lld %p/Inputs/symtab-sh_info2.elf -o %t2 2>&1 | FileCheck %s
+# CHECK: invalid sh_info in symbol table
+
+## sh_info contains invalid value saying non-local symbol is local.
+# RUN: not ld.lld %p/Inputs/symtab-sh_info3.elf -o %t2 2>&1 | \
+# RUN:   FileCheck --check-prefix=INVALID-SYMTAB-SHINFO %s
+# INVALID-SYMTAB-SHINFO: broken object: getLocalSymbols returns a non-local symbol
diff --git a/test/ELF/invalid/symtab-symbols.test b/test/ELF/invalid/symtab-symbols.test
new file mode 100644 (file)
index 0000000..953b2e3
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: yaml2obj %s -o %t
+# RUN: ld.lld -shared %t -o %tout
+
+# GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could generate
+# broken objects.
+# Verify that lld can handle STT_NOTYPE symbols associated
+# with SHT_SYMTAB section.
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_FREEBSD
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         "00000000"
+Symbols:
+  Local:
+    - Type:            STT_NOTYPE
+      Section:         .symtab
diff --git a/test/ELF/invalid/tls-symbol.s b/test/ELF/invalid/tls-symbol.s
new file mode 100644 (file)
index 0000000..354ca57
--- /dev/null
@@ -0,0 +1,5 @@
+# REQUIRES: x86
+
+## The test file contains an STT_TLS symbol but has no TLS section.
+# RUN: not ld.lld %S/Inputs/tls-symbol.elf -o %t 2>&1 | FileCheck %s
+# CHECK: has an STT_TLS symbol but doesn't have an SHF_TLS section
diff --git a/test/ELF/invalid/too-short.s b/test/ELF/invalid/too-short.s
new file mode 100644 (file)
index 0000000..deaf821
--- /dev/null
@@ -0,0 +1,5 @@
+# REQUIRES: x86
+
+## too-short.elf file is a truncated ELF.
+# RUN: not ld.lld %S/Inputs/too-short.elf -o %t 2>&1 | FileCheck %s
+# CHECK: file is too short
diff --git a/test/ELF/invalid/verdef-no-symtab.test b/test/ELF/invalid/verdef-no-symtab.test
new file mode 100644 (file)
index 0000000..5b5c32e
--- /dev/null
@@ -0,0 +1,26 @@
+# RUN: yaml2obj %s -o %t
+# RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+
+## When we have SHT_GNU_versym section, it is should be associated
+## with symbol table section.
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .versym
+    Type:            SHT_GNU_versym
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x1
+    Content:         "00000000"
+
+  - Name:            .verdef
+    Type:            SHT_GNU_verdef
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x1
+    Content:         "00000000"
+
+
+# CHECK: SHT_GNU_versym should be associated with symbol table
diff --git a/test/ELF/libsearch.s b/test/ELF/libsearch.s
new file mode 100644 (file)
index 0000000..32be866
--- /dev/null
@@ -0,0 +1,101 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/libsearch-dyn.s -o %tdyn.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/libsearch-st.s -o %tst.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/use-bar.s -o %tbar.o
+// RUN: mkdir -p %t.dir
+// RUN: ld.lld -shared %tdyn.o -o %t.dir/libls.so
+// RUN: cp -f %t.dir/libls.so %t.dir/libls2.so
+// RUN: rm -f %t.dir/libls.a
+// RUN: llvm-ar rcs %t.dir/libls.a %tst.o
+// REQUIRES: x86
+
+// Should fail if no library specified
+// RUN: not ld.lld -l 2>&1 \
+// RUN:   | FileCheck --check-prefix=NOLIBRARY %s
+// NOLIBRARY: -l: missing argument
+
+// Should link normally, because _bar is not used
+// RUN: ld.lld -o %t3 %t.o
+// Should not link because of undefined symbol _bar
+// RUN: not ld.lld -o %t3 %t.o %tbar.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=UNDEFINED %s
+// UNDEFINED: error: undefined symbol: _bar
+// UNDEFINED: >>> referenced by {{.*}}:(.bar+0x0)
+
+// Should fail if cannot find specified library (without -L switch)
+// RUN: not ld.lld -o %t3 %t.o -lls 2>&1 \
+// RUN:   | FileCheck --check-prefix=NOLIB %s
+// NOLIB: unable to find library -lls
+
+// Should use explicitly specified static library
+// Also ensure that we accept -L <arg>
+// RUN: ld.lld -o %t3 %t.o -L %t.dir -l:libls.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// STATIC: Symbols [
+// STATIC: Name: _static
+// STATIC: ]
+
+// Should use explicitly specified dynamic library
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -l:libls.so
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+// DYNAMIC: Symbols [
+// DYNAMIC-NOT: Name: _static
+// DYNAMIC: ]
+
+// Should prefer dynamic to static
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+
+// Check for library search order
+// RUN: mkdir -p %t.dir2
+// RUN: cp %t.dir/libls.a %t.dir2
+// RUN: ld.lld -o %t3 %t.o -L%t.dir2 -L%t.dir -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+
+// -L can be placed after -l
+// RUN: ld.lld -o %t3 %t.o -lls -L%t.dir
+
+// Check long forms as well
+// RUN: ld.lld -o %t3 %t.o --library-path=%t.dir --library=ls
+
+// Should not search for dynamic libraries if -Bstatic is specified
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: not ld.lld -o %t3 %t.o -L%t.dir -Bstatic -lls2 2>&1 \
+// RUN:   | FileCheck --check-prefix=NOLIB2 %s
+// NOLIB2: unable to find library -lls2
+
+// -Bdynamic should restore default behaviour
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -Bdynamic -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+
+// -Bstatic and -Bdynamic should affect only libraries which follow them
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -lls -Bstatic -Bdynamic
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -lls -Bdynamic
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+
+// Check aliases as well
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -dn -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -non_shared -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -static -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=STATIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -dy -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+// RUN: ld.lld -o %t3 %t.o -L%t.dir -Bstatic -call_shared -lls
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+
+// -nostdlib
+// RUN: echo 'SEARCH_DIR("'%t.dir'")' > %t.script
+// RUN: ld.lld -o %t3 %t.o -script %t.script -lls
+// RUN: not ld.lld -o %t3 %t.o -script %t.script -lls -nostdlib \
+// RUN:   2>&1 | FileCheck --check-prefix=NOSTDLIB %s
+// NOSTDLIB: unable to find library -lls
+
+.globl _start,_bar
+_start:
diff --git a/test/ELF/linkerscript/Inputs/comdat-gc.s b/test/ELF/linkerscript/Inputs/comdat-gc.s
new file mode 100644 (file)
index 0000000..da29d5b
--- /dev/null
@@ -0,0 +1,5 @@
+.file 1 "test/ELF/linkerscript/Inputs/comdat_gc.s"
+
+.section  .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat
+.loc 1 5
+  ret
diff --git a/test/ELF/linkerscript/Inputs/compress-debug-sections.s b/test/ELF/linkerscript/Inputs/compress-debug-sections.s
new file mode 100644 (file)
index 0000000..703be59
--- /dev/null
@@ -0,0 +1,3 @@
+.section .debug_str
+  .asciz "CCC"
+  .asciz "DDD"
diff --git a/test/ELF/linkerscript/Inputs/exclude-multiple1.s b/test/ELF/linkerscript/Inputs/exclude-multiple1.s
new file mode 100644 (file)
index 0000000..1e0f741
--- /dev/null
@@ -0,0 +1,8 @@
+.section .foo.1,"a"
+ .quad 4
+
+.section .foo.2,"a"
+ .quad 5
+
+.section .foo.3,"a"
+ .quad 6
diff --git a/test/ELF/linkerscript/Inputs/exclude-multiple2.s b/test/ELF/linkerscript/Inputs/exclude-multiple2.s
new file mode 100644 (file)
index 0000000..60f790f
--- /dev/null
@@ -0,0 +1,8 @@
+.section .foo.1,"a"
+ .quad 7
+
+.section .foo.2,"a"
+ .quad 8
+
+.section .foo.3,"a"
+ .quad 9
diff --git a/test/ELF/linkerscript/Inputs/filename-spec.s b/test/ELF/linkerscript/Inputs/filename-spec.s
new file mode 100644 (file)
index 0000000..a688b4d
--- /dev/null
@@ -0,0 +1,2 @@
+.section .foo,"a"
+  .quad 0x11
diff --git a/test/ELF/linkerscript/Inputs/implicit-program-header.script b/test/ELF/linkerscript/Inputs/implicit-program-header.script
new file mode 100644 (file)
index 0000000..27dbea8
--- /dev/null
@@ -0,0 +1,12 @@
+PHDRS
+{
+       ph_write PT_LOAD FLAGS(2);
+       ph_exec  PT_LOAD FLAGS(1);
+}
+
+SECTIONS
+{
+  .bar : { *(.bar) } : ph_exec
+  .foo : { *(.foo) }
+  .text : { *(.text) } : ph_write
+}
diff --git a/test/ELF/linkerscript/Inputs/include.s b/test/ELF/linkerscript/Inputs/include.s
new file mode 100644 (file)
index 0000000..a2f809b
--- /dev/null
@@ -0,0 +1,5 @@
+.section .text
+.globl _potato
+_potato:
+  nop
+  nop
diff --git a/test/ELF/linkerscript/Inputs/keep.s b/test/ELF/linkerscript/Inputs/keep.s
new file mode 100644 (file)
index 0000000..20fa41c
--- /dev/null
@@ -0,0 +1,2 @@
+.section .keep, "a"
+ .long 0x41414141
diff --git a/test/ELF/linkerscript/Inputs/lazy-symbols.s b/test/ELF/linkerscript/Inputs/lazy-symbols.s
new file mode 100644 (file)
index 0000000..dd28fcb
--- /dev/null
@@ -0,0 +1,2 @@
+.globl foo
+foo:
diff --git a/test/ELF/linkerscript/Inputs/libsearch-dyn.s b/test/ELF/linkerscript/Inputs/libsearch-dyn.s
new file mode 100644 (file)
index 0000000..091b3b9
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _bar,_dynamic
+_bar:
+_dynamic:
diff --git a/test/ELF/linkerscript/Inputs/libsearch-st.s b/test/ELF/linkerscript/Inputs/libsearch-st.s
new file mode 100644 (file)
index 0000000..6da62f7
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _bar,_static
+_bar:
+_static:
diff --git a/test/ELF/linkerscript/Inputs/merge-sections-reloc.s b/test/ELF/linkerscript/Inputs/merge-sections-reloc.s
new file mode 100644 (file)
index 0000000..07e599b
--- /dev/null
@@ -0,0 +1,3 @@
+.globl _start
+_start:
+ .quad 0x11223344
diff --git a/test/ELF/linkerscript/Inputs/notinclude.s b/test/ELF/linkerscript/Inputs/notinclude.s
new file mode 100644 (file)
index 0000000..46c0509
--- /dev/null
@@ -0,0 +1,4 @@
+.section .text
+.globl tomato
+tomato:
+  movl $1, %eax
diff --git a/test/ELF/linkerscript/Inputs/segment-start.script b/test/ELF/linkerscript/Inputs/segment-start.script
new file mode 100644 (file)
index 0000000..9f1a593
--- /dev/null
@@ -0,0 +1,7 @@
+SECTIONS
+{
+  PROVIDE (foobar1 = SEGMENT_START("text-segment", 0x8001));
+  PROVIDE (foobar2 = SEGMENT_START("data-segment", 0x8002));
+  PROVIDE (foobar3 = SEGMENT_START("bss-segment", 0x8000 + (4 - 1)));
+  PROVIDE (foobar4 = SEGMENT_START("abc-segment", 0x8004));
+}
diff --git a/test/ELF/linkerscript/Inputs/shared.s b/test/ELF/linkerscript/Inputs/shared.s
new file mode 100644 (file)
index 0000000..c3c22fe
--- /dev/null
@@ -0,0 +1,10 @@
+.global bar
+.type bar, @function
+bar:
+
+.global bar2
+.type bar2, @function
+bar2:
+
+.global zed
+zed:
diff --git a/test/ELF/linkerscript/Inputs/sort-nested.s b/test/ELF/linkerscript/Inputs/sort-nested.s
new file mode 100644 (file)
index 0000000..c42fa9c
--- /dev/null
@@ -0,0 +1,7 @@
+.section .aaa.1, "a"
+.align 16
+.quad 0x11
+
+.section .aaa.2, "a"
+.align 4
+.quad 0x22
diff --git a/test/ELF/linkerscript/Inputs/sort.s b/test/ELF/linkerscript/Inputs/sort.s
new file mode 100644 (file)
index 0000000..22e65ad
--- /dev/null
@@ -0,0 +1,19 @@
+.section .aaa.5, "a"
+.align 2
+.quad 0x55
+
+.section .aaa.1, "a"
+.align 32
+.quad 0x11
+
+.section .aaa.3, "a"
+.align 8
+.quad 0x33
+
+.section .aaa.2, "a"
+.align 16
+.quad 0x22
+
+.section .aaa.4, "a"
+.align 4
+.quad 0x44
diff --git a/test/ELF/linkerscript/absolute-expr.s b/test/ELF/linkerscript/absolute-expr.s
new file mode 100644 (file)
index 0000000..a9a674b
--- /dev/null
@@ -0,0 +1,82 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:                  .text : { \
+# RUN:                    bar1 = ALIGNOF(.text); \
+# RUN:                    bar2 = CONSTANT (MAXPAGESIZE); \
+# RUN:                    bar3 = SIZEOF (.text); \
+# RUN:                    bar4 = SIZEOF_HEADERS; \
+# RUN:                    bar5 = 0x42; \
+# RUN:                    bar6 = foo + 1; \
+# RUN:                    *(.text) \
+# RUN:                  } \
+# RUN:                };" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-readobj -t %t.so | FileCheck %s
+
+.global foo
+foo = 0x123
+
+# CHECK:      Symbol {
+# CHECK:        Name: foo
+# CHECK-NEXT:   Value: 0x123
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Absolute (0xFFF1)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: bar1
+# CHECK-NEXT:   Value: 0x4
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: bar2
+# CHECK-NEXT:   Value: 0x1000
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: bar3
+# CHECK-NEXT:   Value: 0x0
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: bar4
+# CHECK-NEXT:   Value: 0x190
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: bar5
+# CHECK-NEXT:   Value: 0x42
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: bar6
+# CHECK-NEXT:   Value: 0x124
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global (0x1)
+# CHECK-NEXT:   Type: None (0x0)
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Absolute (0xFFF1)
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/absolute.s b/test/ELF/linkerscript/absolute.s
new file mode 100644 (file)
index 0000000..54f1c70
--- /dev/null
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { foo = ABSOLUTE(.) + 1; };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj --symbols %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "PROVIDE(foo = 1 + ABSOLUTE(ADDR(.text)));" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj --symbols %t | FileCheck --check-prefix=CHECK-RHS %s
+
+# CHECK:        Name: foo
+# CHECK-NEXT:   Value:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding:
+# CHECK-NEXT:   Type:
+# CHECK-NEXT:   Other:
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
+
+# CHECK-RHS:        Name: foo
+# CHECK-RHS-NEXT:   Value: 0x201001
+# CHECK-RHS-NEXT:   Size:
+# CHECK-RHS-NEXT:   Binding:
+# CHECK-RHS-NEXT:   Type:
+# CHECK-RHS-NEXT:   Other:
+# CHECK-RHS-NEXT:   Section: Absolute
+# CHECK-RHS-NEXT: }
+
+.text
+.globl _start
+_start:
+ nop
+
+.global foo
diff --git a/test/ELF/linkerscript/addr-zero.s b/test/ELF/linkerscript/addr-zero.s
new file mode 100644 (file)
index 0000000..71251d3
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { foo = ADDR(.text) - ABSOLUTE(ADDR(.text)); };" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-readobj --symbols %t.so | FileCheck %s
+
+# Test that the script creates a non absolute symbol with value
+# 0 I.E., a symbol that refers to the load address.
+
+# CHECK:      Symbol {
+# CHECK:        Name: foo
+# CHECK-NEXT:   Value: 0x0
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: .text
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/addr.s b/test/ELF/linkerscript/addr.s
new file mode 100644 (file)
index 0000000..2d3a7ab
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x1000; \
+# RUN:  .text  : { *(.text*) } \
+# RUN: .foo.1 : { *(.foo.1) }  \
+# RUN: .foo.2 ADDR(.foo.1) + 0x100 : { *(.foo.2) } \
+# RUN: .foo.3 : { *(.foo.3) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t1
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .text         00000000 0000000000001000 TEXT DATA
+# CHECK-NEXT:   2 .foo.1        00000008 0000000000001000 DATA
+# CHECK-NEXT:   3 .foo.2        00000008 0000000000001100 DATA
+# CHECK-NEXT:   4 .foo.3        00000008 0000000000001108 DATA
+
+.text
+.globl _start
+_start:
+
+.section .foo.1,"a"
+ .quad 1
+
+.section .foo.2,"a"
+ .quad 2
+
+.section .foo.3,"a"
+ .quad 3
diff --git a/test/ELF/linkerscript/align-empty.s b/test/ELF/linkerscript/align-empty.s
new file mode 100644 (file)
index 0000000..3ff7157
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN:  abc : { } \
+# RUN:  . = ALIGN(0x1000); \
+# RUN:  foo : { *(foo) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 foo           00000001 0000000000001000
+
+        .section foo, "a"
+        .byte 0
diff --git a/test/ELF/linkerscript/align.s b/test/ELF/linkerscript/align.s
new file mode 100644 (file)
index 0000000..357f54c
--- /dev/null
@@ -0,0 +1,80 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check that ALIGN command workable using location counter
+# RUN: echo "SECTIONS {      \
+# RUN:  . = 0x10000;         \
+# RUN:  .aaa : { *(.aaa) }   \
+# RUN:  . = ALIGN(4096);     \
+# RUN:  .bbb : { *(.bbb) }   \
+# RUN:  . = ALIGN(4096 * 4); \
+# RUN:  .ccc : { *(.ccc) }   \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+## Check that the two argument version of ALIGN command works
+# RUN: echo "SECTIONS {             \
+# RUN:  . = ALIGN(0x1234, 0x10000); \
+# RUN:  .aaa : { *(.aaa) }          \
+# RUN:  . = ALIGN(., 4096);         \
+# RUN:  .bbb : { *(.bbb) }          \
+# RUN:  . = ALIGN(., 4096 * 4);     \
+# RUN:  .ccc : { *(.ccc) }          \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .aaa          00000008 0000000000010000 DATA
+# CHECK-NEXT:   2 .bbb          00000008 0000000000011000 DATA
+# CHECK-NEXT:   3 .ccc          00000008 0000000000014000 DATA
+
+## Check output sections ALIGN modificator
+# RUN: echo "SECTIONS {                    \
+# RUN:  . = 0x10000;                       \
+# RUN:  .aaa : { *(.aaa) }                 \
+# RUN:  .bbb : ALIGN(4096) { *(.bbb) }     \
+# RUN:  .ccc : ALIGN(4096 * 4) { *(.ccc) } \
+# RUN: }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
+
+## Check use of variables in align expressions:
+# RUN: echo "VAR = 0x1000;                                  \
+# RUN: __code_base__ = 0x10000;                             \
+# RUN: SECTIONS {                                           \
+# RUN:  . = __code_base__;                                  \
+# RUN:  .aaa : { *(.aaa) }                                  \
+# RUN:  .bbb : ALIGN(VAR) { *(.bbb) }                       \
+# RUN:  . = ALIGN(., VAR * 4);                              \
+# RUN:  .ccc : { *(.ccc) }                                  \
+# RUN:  __start_bbb = ADDR(.bbb);                           \
+# RUN:  __end_bbb = ALIGN(__start_bbb + SIZEOF(.bbb), VAR); \
+# RUN: }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %t
+# RUN: llvm-objdump -section-headers %t3 | FileCheck %s
+# RUN: llvm-objdump -t %t3 | FileCheck -check-prefix SYMBOLS %s
+
+# SYMBOLS-LABEL: SYMBOL TABLE:
+# SYMBOLS-NEXT: 0000000000000000         *UND*           00000000
+# SYMBOLS-NEXT: 0000000000014008         .text           00000000 _start
+# SYMBOLS-NEXT: 0000000000010000         *ABS*           00000000 __code_base__
+# SYMBOLS-NEXT: 0000000000001000         *ABS*           00000000 VAR
+# SYMBOLS-NEXT: 0000000000011000         .bbb            00000000 __start_bbb
+# SYMBOLS-NEXT: 0000000000012000         .bbb            00000000 __end_bbb
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/alignof.s b/test/ELF/linkerscript/alignof.s
new file mode 100644 (file)
index 0000000..8880634
--- /dev/null
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:   .aaa         : { *(.aaa) } \
+# RUN:   .bbb         : { *(.bbb) } \
+# RUN:   .ccc         : { *(.ccc) } \
+# RUN:   _aaa = ALIGNOF(.aaa); \
+# RUN:   _bbb = ALIGNOF(.bbb); \
+# RUN:   _ccc = ALIGNOF(.ccc); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK:      SYMBOL TABLE:
+# CHECK:      0000000000000008         *ABS*     00000000 _aaa
+# CHECK-NEXT: 0000000000000010         *ABS*     00000000 _bbb
+# CHECK-NEXT: 0000000000000020         *ABS*     00000000 _ccc
+
+## Check that we error out if trying to get alignment of
+## section that does not exist.
+# RUN: echo "SECTIONS { \
+# RUN:   _aaa = ALIGNOF(.foo); \
+# RUN: }" > %t.script
+# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR %s
+# ERR: {{.*}}.script:1: undefined section .foo
+.global _start
+_start:
+ nop
+
+.section .aaa,"a"
+ .align 8
+ .quad 0
+
+.section .bbb,"a"
+ .align 16
+ .quad 0
+
+.section .ccc,"a"
+ .align 32
+ .quad 0
diff --git a/test/ELF/linkerscript/alternate-sections.s b/test/ELF/linkerscript/alternate-sections.s
new file mode 100644 (file)
index 0000000..fd74a8a
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { abc : { *(foo) *(bar) *(zed) } }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+# CHECK:       Section {
+# CHECK:        Index:
+# CHECK:        Name: abc
+# CHECK-NEXT:   Type: SHT_PROGBIT
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:     SHF_STRINGS
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: 01000000 00000000 61626331 32330002  |........abc123..|
+# CHECK-NEXT:     0010: 00000000 000000                      |.......|
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+
+        .section foo, "a"
+        .quad 1
+
+        .section bar,"aMS",@progbits,1
+        .asciz  "abc123"
+
+        .section zed, "a"
+        .quad 2
diff --git a/test/ELF/linkerscript/arm-exidx-phdrs.s b/test/ELF/linkerscript/arm-exidx-phdrs.s
new file mode 100644 (file)
index 0000000..971702f
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: echo "PHDRS { ph_text PT_LOAD; } \
+// RUN:       SECTIONS { \
+// RUN:         . = SIZEOF_HEADERS; \
+// RUN:         .text : { *(.text) } : ph_text \
+// RUN:       }" > %t.script
+// RUN: ld.lld -T %t.script %t.o -shared -o %t.so
+// RUN: llvm-readobj --program-headers %t.so | FileCheck %s
+
+// CHECK: Type: PT_ARM_EXIDX
+
+.fnstart
+bx      lr
+.cantunwind
+.fnend
diff --git a/test/ELF/linkerscript/arm-lscript.s b/test/ELF/linkerscript/arm-lscript.s
new file mode 100644 (file)
index 0000000..c377764
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: echo  "SECTIONS { \
+// RUN:         .rel.dyn : {    } \
+// RUN:         .zed     : { PROVIDE_HIDDEN (foobar = .); } \
+// RUN:         }" > %t.script
+// This is a test case for PR33029. Making sure that linker can digest
+// the above script without dumping core.
+// RUN: ld.lld -emit-relocs -T %t.script %t.o -shared -o %t.so
diff --git a/test/ELF/linkerscript/assert.s b/test/ELF/linkerscript/assert.s
new file mode 100644 (file)
index 0000000..73cc940
--- /dev/null
@@ -0,0 +1,39 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: echo "SECTIONS { ASSERT(1, fail) }" > %t1.script
+# RUN: ld.lld -shared -o %t1 --script %t1.script %t1.o
+# RUN: llvm-readobj %t1 > /dev/null
+
+# RUN: echo "SECTIONS { ASSERT(0, fail) }" > %t3.script
+# RUN: not ld.lld -shared -o %t3 --script %t3.script %t1.o > %t.log 2>&1
+# RUN: FileCheck %s -check-prefix=FAIL < %t.log
+# FAIL: fail
+
+# RUN: echo "SECTIONS { . = ASSERT(0x1000, fail); }" > %t4.script
+# RUN: ld.lld -shared -o %t4 --script %t4.script %t1.o
+# RUN: llvm-readobj %t4 > /dev/null
+
+# RUN: echo "SECTIONS { .foo : { *(.foo) } }" > %t5.script
+# RUN: echo "ASSERT(SIZEOF(.foo) == 8, fail);" >> %t5.script
+# RUN: ld.lld -shared -o %t5 --script %t5.script %t1.o
+# RUN: llvm-readobj %t5 > /dev/null
+
+## Even without SECTIONS block we still use section names
+## in expressions
+# RUN: echo "ASSERT(SIZEOF(.foo) == 8, fail);" > %t5.script
+# RUN: ld.lld -shared -o %t5 --script %t5.script %t1.o
+# RUN: llvm-readobj %t5 > /dev/null
+
+## Test assertions inside of output section decriptions.
+# RUN: echo "SECTIONS { .foo : { *(.foo) ASSERT(SIZEOF(.foo) == 8, \"true\"); } }" > %t6.script
+# RUN: ld.lld -shared -o %t6 --script %t6.script %t1.o
+# RUN: llvm-readobj %t6 > /dev/null
+
+# RUN: echo "SECTIONS { .foo : { ASSERT(1, \"true\") } }" > %t7.script
+# RUN: not ld.lld -shared -o %t7 --script %t7.script %t1.o > %t.log 2>&1
+# RUN: FileCheck %s -check-prefix=CHECK-SEMI < %t.log
+# CHECK-SEMI: error: {{.*}}.script:1: ; expected, but got }
+
+.section .foo, "a"
+ .quad 0
diff --git a/test/ELF/linkerscript/at-addr.s b/test/ELF/linkerscript/at-addr.s
new file mode 100644 (file)
index 0000000..0eddf3d
--- /dev/null
@@ -0,0 +1,39 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { . = 0x1000; \
+# RUN:  .aaa : AT(ADDR(.aaa) - 0x500) { *(.aaa) } \
+# RUN:  .bbb : AT(ADDR(.bbb) - 0x500) { *(.bbb) } \
+# RUN:  .ccc : AT(ADDR(.ccc) - 0x500) { *(.ccc) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK:      Type: PT_LOAD
+# CHECK-NEXT:   Offset: 0x0
+# CHECK-NEXT:   VirtualAddress: 0x0
+# CHECK-NEXT:   PhysicalAddress: 0x0
+# CHECK:      Type: PT_LOAD
+# CHECK-NEXT:   Offset: 0x1000
+# CHECK-NEXT:   VirtualAddress: 0x1000
+# CHECK-NEXT:   PhysicalAddress: 0xB00
+# CHECK:      Type: PT_LOAD
+# CHECK-NEXT:   Offset: 0x1008
+# CHECK-NEXT:   VirtualAddress: 0x1008
+# CHECK-NEXT:   PhysicalAddress: 0xB08
+# CHECK:      Type: PT_LOAD
+# CHECK-NEXT:   Offset: 0x1010
+# CHECK-NEXT:   VirtualAddress: 0x1010
+# CHECK-NEXT:   PhysicalAddress: 0xB10
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/at.s b/test/ELF/linkerscript/at.s
new file mode 100644 (file)
index 0000000..26441f1
--- /dev/null
@@ -0,0 +1,124 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x1000; \
+# RUN:  .aaa : AT(0x2000) { *(.aaa) } \
+# RUN:  .bbb : { *(.bbb) } \
+# RUN:  .ccc : AT(0x3000) { *(.ccc) } \
+# RUN:  .ddd : AT(0x4000) { *(.ddd) } \
+# RUN:  .eee 0x5000 : AT(0x5000) { *(.eee) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x40
+# CHECK-NEXT:     PhysicalAddress: 0x40
+# CHECK-NEXT:     FileSize:
+# CHECK-NEXT:     MemSize:
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize:
+# CHECK-NEXT:     MemSize:
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_X
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x1000
+# CHECK-NEXT:     VirtualAddress: 0x1000
+# CHECK-NEXT:     PhysicalAddress: 0x2000
+# CHECK-NEXT:     FileSize: 16
+# CHECK-NEXT:     MemSize: 16
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_X
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x1010
+# CHECK-NEXT:     VirtualAddress: 0x1010
+# CHECK-NEXT:     PhysicalAddress: 0x3000
+# CHECK-NEXT:     FileSize: 8
+# CHECK-NEXT:     MemSize: 8
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_X
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x1018
+# CHECK-NEXT:     VirtualAddress: 0x1018
+# CHECK-NEXT:     PhysicalAddress: 0x4000
+# CHECK-NEXT:     FileSize: 8
+# CHECK-NEXT:     MemSize: 8
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_X
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x2000
+# CHECK-NEXT:     VirtualAddress: 0x5000
+# CHECK-NEXT:     PhysicalAddress: 0x5000
+# CHECK-NEXT:     FileSize: 9
+# CHECK-NEXT:     MemSize: 9
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_X
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset:
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize:
+# CHECK-NEXT:     MemSize:
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
+
+.section .ddd, "a"
+.quad 0
+
+.section .eee, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/bss-fill.s b/test/ELF/linkerscript/bss-fill.s
new file mode 100644 (file)
index 0000000..92f9fdf
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .bss : { . += 0x10000; *(.bss) } =0xFF };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+
+.section .bss,"",@nobits
+.short 0
diff --git a/test/ELF/linkerscript/comdat-gc.s b/test/ELF/linkerscript/comdat-gc.s
new file mode 100644 (file)
index 0000000..63dcf85
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/comdat-gc.s -o %t1
+# RUN: echo "SECTIONS { .text : { *(.text*) } }" > %t.script
+# RUN: ld.lld --gc-sections --script %t.script %t %t1 -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC1 %s
+
+# GC1:     Name: .debug_line
+
+.file 1 "test/ELF/linkerscript/comdat_gc.s"
+.section  .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat
+.loc 1 14
+  ret
diff --git a/test/ELF/linkerscript/common-assign.s b/test/ELF/linkerscript/common-assign.s
new file mode 100644 (file)
index 0000000..4244ae3
--- /dev/null
@@ -0,0 +1,48 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; pfoo = foo; pbar = bar; }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -symbols %t1 | FileCheck %s
+
+# CHECK:       Symbol {
+# CHECK:         Name: bar
+# CHECK-NEXT:     Value: 0x134
+# CHECK-NEXT:     Size: 4
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .bss
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value: 0x138
+# CHECK-NEXT:     Size: 4
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .bss
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: pfoo
+# CHECK-NEXT:     Value: 0x138
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .bss
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: pbar
+# CHECK-NEXT:     Value: 0x134
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .bss
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.comm  foo,4,4
+.comm  bar,4,4
+movl   $1, foo(%rip)
+movl   $2, bar(%rip)
diff --git a/test/ELF/linkerscript/common.s b/test/ELF/linkerscript/common.s
new file mode 100644 (file)
index 0000000..2e5972d
--- /dev/null
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .common : { *(COMMON) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -s -t %t1 | FileCheck %s
+
+# q2 alignment is greater than q1, so it should have smaller offset
+# because of sorting
+# CHECK:       Section {
+# CHECK:         Index:
+# CHECK:         Name: .common
+# CHECK-NEXT:    Type: SHT_NOBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x200
+# CHECK-NEXT:    Offset: 0x
+# CHECK-NEXT:    Size: 256
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 256
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK:       Symbol {
+# CHECK:         Name: q1
+# CHECK-NEXT:    Value: 0x280
+# CHECK-NEXT:    Size: 128
+# CHECK-NEXT:    Binding: Global
+# CHECK-NEXT:    Type: Object
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: .common
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Symbol {
+# CHECK-NEXT:    Name: q2
+# CHECK-NEXT:    Value: 0x200
+# CHECK-NEXT:    Size: 128
+# CHECK-NEXT:    Binding: Global
+# CHECK-NEXT:    Type: Object
+# CHECK-NEXT:    Other: 0
+# CHECK-NEXT:    Section: .common
+# CHECK-NEXT:  }
+
+.globl _start
+_start:
+  jmp _start
+
+.comm q1,128,8
+.comm q2,128,256
diff --git a/test/ELF/linkerscript/compress-debug-sections.s b/test/ELF/linkerscript/compress-debug-sections.s
new file mode 100644 (file)
index 0000000..6798a21
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86, zlib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %S/Inputs/compress-debug-sections.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+
+## .debug_str section is mergeable. LLD would combine all of them into single
+## mergeable synthetic section. We use -O0 here to disable merging, that
+## allows to check that input sections has correctly assigned offsets.
+
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: ld.lld -O0 %t1.o %t2.o %t.script -o %t1 --compress-debug-sections=zlib
+# RUN: llvm-dwarfdump %t1 | FileCheck %s
+# RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=ZLIBFLAGS
+
+# RUN: echo "SECTIONS { .debug_str 0 : { *(.debug_str) } }" > %t2.script
+# RUN: ld.lld -O0 %t1.o %t2.o %t2.script -o %t2 --compress-debug-sections=zlib
+# RUN: llvm-dwarfdump %t2 | FileCheck %s
+# RUN: llvm-readobj -s %t2 | FileCheck %s --check-prefix=ZLIBFLAGS
+
+# CHECK:       .debug_str contents:
+# CHECK-NEXT:    CCC
+# CHECK-NEXT:    DDD
+# CHECK-NEXT:    AAA
+# CHECK-NEXT:    BBB
+
+# ZLIBFLAGS:       Section {
+# ZLIBFLAGS:         Index:
+# ZLIBFLAGS:         Name: .debug_str
+# ZLIBFLAGS-NEXT:    Type: SHT_PROGBITS
+# ZLIBFLAGS-NEXT:    Flags [
+# ZLIBFLAGS-NEXT:      SHF_COMPRESSED
+
+.section .debug_str
+  .asciz "AAA"
+  .asciz "BBB"
diff --git a/test/ELF/linkerscript/constructor.s b/test/ELF/linkerscript/constructor.s
new file mode 100644 (file)
index 0000000..acb86fd
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { foo : { *(.foo) CONSTRUCTORS } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t.o
+
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size
+# CHECK-NEXT:   0               00000000
+# CHECK-NEXT:   1 foo           00000001
+
+.section foo, "a"
+.byte 0
diff --git a/test/ELF/linkerscript/data-commands-gc.s b/test/ELF/linkerscript/data-commands-gc.s
new file mode 100644 (file)
index 0000000..1afcc9a
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { *(.text*) QUAD(bar) } }" > %t.script
+# RUN: ld.lld --gc-sections -o %t %t.o --script %t.script
+# RUN: llvm-objdump -t %t | FileCheck %s
+
+# CHECK: 0000000000000011         .rodata                 00000000 bar
+
+.section .rodata.bar
+.quad 0x1122334455667788
+.global bar
+bar:
+
+.section .text
+.global _start
+_start:
+  nop
diff --git a/test/ELF/linkerscript/data-commands.s b/test/ELF/linkerscript/data-commands.s
new file mode 100644 (file)
index 0000000..ef154ed
--- /dev/null
@@ -0,0 +1,81 @@
+# REQUIRES: x86,mips
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS                \
+# RUN:  {                            \
+# RUN:    .foo : {                   \
+# RUN:      *(.foo.1)                \
+# RUN:      BYTE(0x11)               \
+# RUN:      *(.foo.2)                \
+# RUN:      SHORT(0x1122)            \
+# RUN:      *(.foo.3)                \
+# RUN:      LONG(0x11223344)         \
+# RUN:      *(.foo.4)                \
+# RUN:      QUAD(0x1122334455667788) \
+# RUN:    }                          \
+# RUN:    .bar : {                   \
+# RUN:      *(.bar.1)                \
+# RUN:      BYTE(a + 1)              \
+# RUN:      *(.bar.2)                \
+# RUN:      SHORT(b)                 \
+# RUN:      *(.bar.3)                \
+# RUN:      LONG(c + 2)              \
+# RUN:      *(.bar.4)                \
+# RUN:      QUAD(d)                  \
+# RUN:    }                          \
+# RUN:  }" > %t.script
+# RUN: ld.lld -o %t %t.o --script %t.script
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK:      Contents of section .foo:
+# CHECK-NEXT:   ff11ff22 11ff4433 2211ff88 77665544
+# CHECK-NEXT:   332211
+
+# CHECK:      Contents of section .bar:
+# CHECK-NEXT:   ff12ff22 11ff4633 2211ff88 77665544
+# CHECK-NEXT:   332211
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %tmips64be
+# RUN: ld.lld --script %t.script %tmips64be -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=BE
+# BE:      Contents of section .foo:
+# BE-NEXT:   ff11ff11 22ff1122 3344ff11 22334455
+# BE-NEXT:   667788
+# BE-NEXT: Contents of section .bar:
+# BE-NEXT:   ff12ff11 22ff1122 3346ff11 22334455
+# BE-NEXT:   667788
+
+.global a
+a = 0x11
+
+.global b
+b = 0x1122
+
+.global c
+c = 0x11223344
+
+.global d
+d = 0x1122334455667788
+
+.section .foo.1, "a"
+ .byte 0xFF
+
+.section .foo.2, "a"
+ .byte 0xFF
+
+.section .foo.3, "a"
+ .byte 0xFF
+
+.section .foo.4, "a"
+ .byte 0xFF
+
+.section .bar.1, "a"
+ .byte 0xFF
+
+.section .bar.2, "a"
+ .byte 0xFF
+
+.section .bar.3, "a"
+ .byte 0xFF
+
+.section .bar.4, "a"
+ .byte 0xFF
diff --git a/test/ELF/linkerscript/data-segment-relro.s b/test/ELF/linkerscript/data-segment-relro.s
new file mode 100644 (file)
index 0000000..7f69319
--- /dev/null
@@ -0,0 +1,70 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN:  .plt  : { *(.plt) } \
+# RUN:  .text : { *(.text) } \
+# RUN:  . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); \
+# RUN:  .dynamic        : { *(.dynamic) } \
+# RUN:  .got            : { *(.got) } \
+# RUN:  . = DATA_SEGMENT_RELRO_END (1 ? 24 : 0, .); \
+# RUN:  .got.plt : { *(.got.plt) } \
+# RUN:  .data : { *(.data) } \
+# RUN:  .bss        : { *(.bss) } \
+# RUN:  . = DATA_SEGMENT_END (.); \
+# RUN:  }" > %t.script
+
+## With relro or without DATA_SEGMENT_RELRO_END just aligns to
+## page boundary.
+# RUN: ld.lld -z norelro %t1.o %t2.so --script %t.script -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+# RUN: ld.lld -z relro %t1.o %t2.so --script %t.script -o %t2
+# RUN: llvm-readobj -s %t2 | FileCheck %s
+
+# CHECK:       Section {
+# CHECK:         Index:
+# CHECK:         Name: .got
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x10F0
+# CHECK-NEXT:    Offset: 0x10F0
+# CHECK-NEXT:    Size:
+# CHECK-NEXT:    Link:
+# CHECK-NEXT:    Info:
+# CHECK-NEXT:    AddressAlignment:
+# CHECK-NEXT:    EntrySize:
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index:
+# CHECK-NEXT:    Name: .got.plt
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x2000
+# CHECK-NEXT:    Offset: 0x2000
+# CHECK-NEXT:    Size:
+# CHECK-NEXT:    Link:
+# CHECK-NEXT:    Info:
+# CHECK-NEXT:    AddressAlignment:
+# CHECK-NEXT:    EntrySize:
+# CHECK-NEXT:  }
+
+.global _start
+_start:
+  .long bar
+  jmp *bar2@GOTPCREL(%rip)
+
+.section .data,"aw"
+.quad 0
+
+.zero 4
+.section .foo,"aw"
+.section .bss,"",@nobits
diff --git a/test/ELF/linkerscript/define.s b/test/ELF/linkerscript/define.s
new file mode 100644 (file)
index 0000000..b5f0b76
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS                                \
+# RUN: {                                             \
+# RUN:  . = DEFINED(defined) ? 0x11000 : .;          \
+# RUN:  .foo : { *(.foo*) }                          \
+# RUN:  . = DEFINED(notdefined) ? 0x12000 : 0x13000; \
+# RUN:  .bar : { *(.bar*) }                          \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK: 1 .foo  00000008 0000000000011000 DATA
+# CHECK: 2 .bar  00000008 0000000000013000 DATA
+# CHECK: 3 .text 00000000 0000000000013008 TEXT DATA
+
+.global defined
+defined = 0
+
+.section .foo,"a"
+.quad 1
+
+.section .bar,"a"
+.quad 1
diff --git a/test/ELF/linkerscript/diagnostic.s b/test/ELF/linkerscript/diagnostic.s
new file mode 100644 (file)
index 0000000..bd1ebd0
--- /dev/null
@@ -0,0 +1,106 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Take some valid script with multiline comments
+## and check it actually works:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: ld.lld -shared %t -o %t1 --script %t.script
+
+## Change ":" to "+" at line 2, check that error
+## message starts from correct line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text + { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: {{.*}}.script:2:
+
+## Change ":" to "+" at line 3 now, check correct error line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep + { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: {{.*}}.script:3:
+
+## Change ":" to "+" at line 6, after multiline comment,
+## check correct error line number:
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) } /*" >> %t.script
+# RUN: echo "comment line 1" >> %t.script
+# RUN: echo "comment line 2 */" >> %t.script
+# RUN: echo ".temp + { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: {{.*}}.script:6:
+
+## Check that text of lines and pointer to 'bad' token are working ok.
+# RUN: echo "UNKNOWN_TAG {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) }" >> %t.script
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR6 -strict-whitespace %s
+# ERR6:      error: {{.*}}.script:1:
+# ERR6-NEXT: error: {{.*}}.script:1: UNKNOWN_TAG {
+# ERR6-NEXT: error: {{.*}}.script:1: ^
+
+## One more check that text of lines and pointer to 'bad' token are working ok.
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text : { *(.text) }" >> %t.script
+# RUN: echo ".keep : { *(.keep) }" >> %t.script
+# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR7 -strict-whitespace %s
+# ERR7:      error: {{.*}}.script:4: malformed number: .temp
+# ERR7-NEXT: error: {{.*}}.script:4: boom .temp : { *(.temp) } }
+# ERR7-NEXT: error: {{.*}}.script:4:      ^
+
+## Check tokenize() error
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: echo "\"" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR8 -strict-whitespace %s
+# ERR8: {{.*}}.script:2: unclosed quote
+
+## Check tokenize() error in included script file
+# RUN: echo "SECTIONS {}" > %t.script.inc
+# RUN: echo "\"" >> %t.script.inc
+# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR9 -strict-whitespace %s
+# ERR9: {{.*}}.script.inc:2: unclosed quote
+
+## Check error reporting correctness for included files.
+# RUN: echo "SECTIONS {" > %t.script.inc
+# RUN: echo ".text : { *(.text) }" >> %t.script.inc
+# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc
+# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script.inc
+# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR10 -strict-whitespace %s
+# ERR10:      error: {{.*}}.script.inc:4: malformed number: .temp
+# ERR10-NEXT: error: {{.*}}.script.inc:4: boom .temp : { *(.temp) } }
+# ERR10-NEXT: error: {{.*}}.script.inc:4:      ^
+
+## Check error reporting in script with INCLUDE directive.
+# RUN: echo "SECTIONS {" > %t.script.inc
+# RUN: echo ".text : { *(.text) }" >> %t.script.inc
+# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc
+# RUN: echo ".temp : { *(.temp) } }" >> %t.script.inc
+# RUN: echo "/* One line before INCLUDE */" > %t.script
+# RUN: echo "INCLUDE \"%t.script.inc\"" >> %t.script
+# RUN: echo "/* One line ater INCLUDE */" >> %t.script
+# RUN: echo "Error" >> %t.script
+# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR11 -strict-whitespace %s
+# ERR11: error: {{.*}}.script:4: unexpected EOF
diff --git a/test/ELF/linkerscript/discard-interp.s b/test/ELF/linkerscript/discard-interp.s
new file mode 100644 (file)
index 0000000..261509e
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/../Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; } \
+// RUN:       SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } : text }" > %t.script
+// RUN: ld.lld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar --script %t.script --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+
+// CHECK-NOT:        Name: .interp
+
+.global _start
+_start:
diff --git a/test/ELF/linkerscript/discard-print-gc.s b/test/ELF/linkerscript/discard-print-gc.s
new file mode 100644 (file)
index 0000000..2a230e5
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple x86_64-pc-linux %s -o %t.o -filetype=obj
+# RUN: ld.lld -o %t.so --gc-sections %t.o --print-gc-sections -shared 2>&1 | \
+# RUN:   FileCheck -check-prefix=CHECK %s
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.foo) } }" > %t.script
+# RUN: ld.lld -o %t.so -T %t.script %t.o --print-gc-sections -shared 2>&1 | \
+# RUN:   FileCheck -check-prefix=QUIET --allow-empty %s
+
+# RUN: echo "SECTIONS { .foo : { *(.foo) } }" > %t2.script
+# RUN: ld.lld -o %t.so -T %t2.script --gc-sections %t.o --print-gc-sections -shared 2>&1 | \
+# RUN:   FileCheck -check-prefix=CHECK %s
+
+.section .foo,"a"
+.quad 0
+
+# CHECK: removing unused section from '.foo'
+# QUIET-NOT: removing unused section from '.foo'
diff --git a/test/ELF/linkerscript/discard-section-err.s b/test/ELF/linkerscript/discard-section-err.s
new file mode 100644 (file)
index 0000000..5d99555
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.shstrtab) } }" > %t.script
+# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | \
+# RUN:   FileCheck -check-prefix=SHSTRTAB %s
+# SHSTRTAB: discarding .shstrtab section is not allowed
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynamic) } }" > %t.script
+# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
+# RUN:   FileCheck -check-prefix=DYNAMIC %s
+# DYNAMIC: discarding .dynamic section is not allowed
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynsym) } }" > %t.script
+# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
+# RUN:   FileCheck -check-prefix=DYNSYM %s
+# DYNSYM: discarding .dynsym section is not allowed
+
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynstr) } }" > %t.script
+# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
+# RUN:   FileCheck -check-prefix=DYNSTR %s
+# DYNSTR: discarding .dynstr section is not allowed
diff --git a/test/ELF/linkerscript/discard-section-metadata.s b/test/ELF/linkerscript/discard-section-metadata.s
new file mode 100644 (file)
index 0000000..961615d
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.foo) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK-NOT: .foo
+# CHECK-NOT: .bar
+# CHECK-NOT: .zed
+# CHECK-NOT: .moo
+
+## Sections dependency tree for testcase is:
+## (.foo)
+##   | |
+##   | --(.bar)
+##   |
+##   --(.zed)
+##       |
+##       --(.moo)
+##
+
+.section .foo,"a"
+.quad 0
+
+.section .bar,"ao",@progbits,.foo
+.quad 0
+
+.section .zed,"ao",@progbits,.foo
+.quad 0
+
+.section .moo,"ao",@progbits,.zed
+.quad 0
diff --git a/test/ELF/linkerscript/discard-section.s b/test/ELF/linkerscript/discard-section.s
new file mode 100644 (file)
index 0000000..a5af908
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.aaa*) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK-NOT: .aaa
+
+.section .aaa,"a"
+aab:
+  .quad 0
+
+.section .zzz,"a"
+  .quad aab
diff --git a/test/ELF/linkerscript/dot-is-not-abs.s b/test/ELF/linkerscript/dot-is-not-abs.s
new file mode 100644 (file)
index 0000000..4532cd5
--- /dev/null
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { .text : { *(.text) } \
+# RUN:                  foo = .; \
+# RUN:                  .bar : { *(.bar) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t.o -shared
+# RUN: llvm-readobj -t -s -section-data %t1 | FileCheck %s
+
+.hidden foo
+.long foo - .
+
+.section .bar, "a"
+.long 0
+
+# The symbol foo is defined as a position in the file. This means that it is
+# not absolute and it is possible to compute the distance from foo to some other
+# position in the file. The symbol is not really in any output section, but
+# ELF has no magic constant for not absolute, but not in any section.
+# Fortunately the value of a symbol in a non relocatable file is a virtual
+# address, so the section can be arbitrary.
+
+# CHECK:      Section {
+# CHECK:        Index:
+# CHECK:        Name: .text
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_EXECINSTR
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x0
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 4
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: 04000000 |
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+
+# CHECK:      Symbol {
+# CHECK:        Name: foo
+# CHECK-NEXT:   Value: 0x4
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Local
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other [
+# CHECK-NEXT:     STV_HIDDEN
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section: .text
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/double-bss.s b/test/ELF/linkerscript/double-bss.s
new file mode 100644 (file)
index 0000000..c24332f
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; " > %t.script
+# RUN: echo ".text : { *(.text*) }" >> %t.script
+# RUN: echo ".bss1 : { *(.bss) }" >> %t.script
+# RUN: echo ".bss2 : { *(COMMON) }" >> %t.script
+# RUN: echo "}" >> %t.script
+
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      .bss1          00000004 0000000000000122 BSS
+# CHECK-NEXT: .bss2          00000080 0000000000000128 BSS
+
+.globl _start
+_start:
+  jmp _start
+
+.bss
+.zero 4
+
+.comm q,128,8
diff --git a/test/ELF/linkerscript/dynamic-sym.s b/test/ELF/linkerscript/dynamic-sym.s
new file mode 100644 (file)
index 0000000..e3193b1
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "_DYNAMIC = 0x123;" > %t.script
+# RUN: ld.lld -T %t.script %t.o -shared -o %t.so
+# RUN: llvm-readobj -t %t.so | FileCheck %s
+
+# CHECK:      Symbol {
+# CHECK:        Name: _DYNAMIC
+# CHECK-NEXT:   Value: 0x123
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Local
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other [
+# CHECK-NEXT:     STV_HIDDEN
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section: Absolute
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/dynamic.s b/test/ELF/linkerscript/dynamic.s
new file mode 100644 (file)
index 0000000..ab65ab8
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: ld.lld %t1.o %t2.so -o %t
+# RUN: llvm-readobj -dynamic-table %t | FileCheck %s
+
+# CHECK:      DynamicSection [
+# CHECK-NEXT:  Tag                 Type             Name/Value
+# CHECK:       0x0000000000000021  PREINIT_ARRAYSZ  9 (bytes)
+# CHECK:       0x000000000000001B  INIT_ARRAYSZ     8 (bytes)
+# CHECK:       0x000000000000001C  FINI_ARRAYSZ     10 (bytes)
+
+.globl _start
+_start:
+
+.section .init_array,"aw",@init_array
+  .quad 0
+
+.section .preinit_array,"aw",@preinit_array
+  .quad 0
+  .byte 0
+
+.section .fini_array,"aw",@fini_array
+  .quad 0
+  .short 0
diff --git a/test/ELF/linkerscript/early-assign-symbol.s b/test/ELF/linkerscript/early-assign-symbol.s
new file mode 100644 (file)
index 0000000..0626e66
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { aaa = 1 + ABSOLUTE(foo - 1); .text  : { *(.text*) } }" > %t1.script
+# RUN: not ld.lld -o %t --script %t1.script %t.o 2>&1 | FileCheck %s
+
+# RUN: echo "SECTIONS { aaa = ABSOLUTE(foo - 1) + 1; .text  : { *(.text*) } }" > %t2.script
+# RUN: not ld.lld -o %t --script %t2.script %t.o 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}.script:1: unable to evaluate expression: input section .text has no output section assigned
+
+.section .text
+.globl foo
+foo:
diff --git a/test/ELF/linkerscript/edata-etext.s b/test/ELF/linkerscript/edata-etext.s
new file mode 100644 (file)
index 0000000..ab723ce
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s
+# CHECK: error: undefined symbol: _edata
+# CHECK: >>> referenced by {{.*}}:(.text+0x0)
+# CHECK: error: undefined symbol: _etext
+# CHECK: >>> referenced by {{.*}}:(.text+0x8)
+# CHECK: error: undefined symbol: _end
+# CHECK: >>> referenced by {{.*}}:(.text+0x10)
+
+.global _start,_end,_etext,_edata
+.text
+_start:
+ .quad _edata + 0x1
+ .quad _etext + 0x1
+ .quad _end + 0x1
+
+.data
+  .word 1
+.bss
+  .align 4
+  .space 6
diff --git a/test/ELF/linkerscript/eh-frame-hdr.s b/test/ELF/linkerscript/eh-frame-hdr.s
new file mode 100644 (file)
index 0000000..d1545be
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:          .eh_frame_hdr : {} \
+# RUN:          .eh_frame : {} \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -s -section=".eh_frame_hdr" %t1 | FileCheck %s
+
+# CHECK:      011b033b 14000000 01000000 49000000
+# CHECK-NEXT: 30000000
+
+.global _start
+_start:
+ nop
+
+.section .dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
diff --git a/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s b/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s
new file mode 100644 (file)
index 0000000..54c0cc7
--- /dev/null
@@ -0,0 +1,27 @@
+## Check that error is correctly reported when .eh_frame reloc
+## is out of range
+
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "PHDRS { eh PT_LOAD; text PT_LOAD; }  \
+# RUN:       SECTIONS { . = 0x10000; \
+# RUN:         .eh_frame_hdr : { *(.eh_frame_hdr*) } : eh \
+# RUN:         .eh_frame : { *(.eh_frame) } : eh \
+# RUN:         . = 0xF00000000; \
+# RUN:         .text : { *(.text*) } : text \
+# RUN:       }" > %t.script
+# RUN: not ld.lld %t.o -T %t.script -o %t 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}:(.eh_frame+0x20): relocation R_X86_64_PC32 out of range
+
+       .text
+  .globl _start
+_start:
+       .cfi_startproc
+  .cfi_lsda 0, _ex
+  nop
+       .cfi_endproc
+
+  .data
+_ex:
+  .word 0
diff --git a/test/ELF/linkerscript/eh-frame.s b/test/ELF/linkerscript/eh-frame.s
new file mode 100644 (file)
index 0000000..750f74e
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:          .eh_frame : { *(.eh_frame) } \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -s -section=".eh_frame" %t1 | FileCheck %s
+
+# CHECK: 0000 14000000 00000000 017a5200 01781001
+# CHECK-NEXT: 0010 1b0c0708 90010000
+
+.global _start
+_start:
+ nop
+
+.section .dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
diff --git a/test/ELF/linkerscript/ehdr_start.s b/test/ELF/linkerscript/ehdr_start.s
new file mode 100644 (file)
index 0000000..4da158a
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: ld.lld %t.o -script %t.script -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck %s
+# CHECK:    Name: __ehdr_start (1)
+# CHECK-NEXT:    Value: 0x0
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Binding: Local (0x0)
+# CHECK-NEXT:    Type: None (0x0)
+# CHECK-NEXT:    Other [ (0x2)
+# CHECK-NEXT:      STV_HIDDEN (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Section: .text (0x1)
+
+.text
+.global _start, __ehdr_start
+_start:
+       .quad __ehdr_start
diff --git a/test/ELF/linkerscript/emit-reloc.s b/test/ELF/linkerscript/emit-reloc.s
new file mode 100644 (file)
index 0000000..725f314
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .rela.dyn : { *(.rela.data) } }" > %t.script
+# RUN: ld.lld -T %t.script --emit-relocs %t.o -o %t.so -shared
+# RUN: llvm-readobj -r %t.so | FileCheck %s
+
+.data
+.quad .foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x66 R_X86_64_64 .foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section ({{.*}}) .rela.data {
+# CHECK-NEXT:     0x66 R_X86_64_64 .foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/linkerscript/emit-relocs-discard.s b/test/ELF/linkerscript/emit-relocs-discard.s
new file mode 100644 (file)
index 0000000..2f1f6c6
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.bbb) } }" > %t.script
+# RUN: ld.lld --emit-relocs --script %t.script %t.o -o %t1
+# RUN: llvm-readobj -r %t1 | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+
+.section .aaa,"",@progbits
+.Lfoo:
+
+.section .bbb,"",@progbits
+.long .Lfoo
diff --git a/test/ELF/linkerscript/emit-relocs-ehframe-discard.s b/test/ELF/linkerscript/emit-relocs-ehframe-discard.s
new file mode 100644 (file)
index 0000000..9df0e8c
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.eh_frame) } }" > %t.script
+# RUN: ld.lld --emit-relocs --script %t.script %t1.o -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+# CHECK-NOT: .rela.eh_frame
+
+.section .foo,"ax",@progbits
+.cfi_startproc
+.cfi_endproc
diff --git a/test/ELF/linkerscript/emit-relocs-multiple.s b/test/ELF/linkerscript/emit-relocs-multiple.s
new file mode 100644 (file)
index 0000000..b04ca1b
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .zed : { *(.foo) *(.bar) } }" > %t.script
+# RUN: ld.lld --emit-relocs --script %t.script %t.o -o %t1
+# RUN: llvm-readobj -r %t1 | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section {{.*}} .rela.foo {
+# CHECK-NEXT:     0x1 R_X86_64_32 .zed 0x0
+# CHECK-NEXT:     0x6 R_X86_64_32 .zed 0x5
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.section .foo,"ax",@progbits
+aaa:
+  movl $aaa, %edx
+
+.section .bar,"ax",@progbits
+bbb:
+  movl $bbb, %edx
diff --git a/test/ELF/linkerscript/empty-load.s b/test/ELF/linkerscript/empty-load.s
new file mode 100644 (file)
index 0000000..ea58d71
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { .rw : { *(.rw) } .text : { *(.text) }  }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -private-headers %t1 | FileCheck %s
+
+## We expect 2 PT_LOAD segments
+# CHECK:     Program Header:
+# CHECK-NEXT:  LOAD
+# CHECK-NEXT:     filesz {{0x[0-9a-f]+}} memsz {{0x[0-9a-f]+}} flags rw-
+# CHECK-NEXT:  LOAD
+# CHECK-NEXT:     filesz {{0x[0-9a-f]+}} memsz {{0x[0-9a-f]+}} flags r-x
+# CHECK-NEXT:  STACK
+# CHECK-NEXT:     filesz
+
+.globl _start
+_start:
+  jmp _start
+
+.section .rw, "aw"
+ .quad 0
diff --git a/test/ELF/linkerscript/empty-tls.s b/test/ELF/linkerscript/empty-tls.s
new file mode 100644 (file)
index 0000000..919ccbf
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: echo  "PHDRS { ph_tls PT_TLS; }" > %t.script
+// RUN: ld.lld -o %t.so -T %t.script %t.o -shared
+// RUN: llvm-readobj -l %t.so | FileCheck %s
+
+// test that we don't crash with an empty PT_TLS
+
+// CHECK:      Type: PT_TLS
+// CHECK-NEXT: Offset: 0x0
+// CHECK-NEXT: VirtualAddress: 0x0
+// CHECK-NEXT: PhysicalAddress: 0x0
+// CHECK-NEXT: FileSize: 0
+// CHECK-NEXT: MemSize: 0
diff --git a/test/ELF/linkerscript/entry.s b/test/ELF/linkerscript/entry.s
new file mode 100644 (file)
index 0000000..d75b134
--- /dev/null
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "ENTRY(_label)" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t
+# RUN: llvm-readobj %t2 > /dev/null
+
+# The entry symbol should not cause an undefined error.
+# RUN: echo "ENTRY(_wrong_label)" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t
+# RUN: ld.lld --entry=abc -o %t2 %t
+
+# -e has precedence over linker script's ENTRY.
+# RUN: echo "ENTRY(_label)" > %t.script
+# RUN: ld.lld -e _start -o %t2 %t.script %t
+# RUN: llvm-readobj -file-headers -symbols %t2 | \
+# RUN:   FileCheck -check-prefix=OVERLOAD %s
+
+# OVERLOAD: Entry: [[ENTRY:0x[0-9A-F]+]]
+# OVERLOAD: Name: _start
+# OVERLOAD-NEXT: Value: [[ENTRY]]
+
+# The entry symbol can be a linker-script-defined symbol.
+# RUN: echo "ENTRY(foo); foo = 1;" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t
+# RUN: llvm-readobj -file-headers -symbols %t2 | \
+# RUN:   FileCheck -check-prefix=SCRIPT %s
+
+# SCRIPT: Entry: 0x1
+
+# RUN: echo "ENTRY(no_such_symbol);" > %t.script
+# RUN: ld.lld -o %t2 %t.script %t 2>&1 | \
+# RUN:   FileCheck -check-prefix=MISSING %s
+
+# MISSING: warning: cannot find entry symbol no_such_symbol
+
+.globl _start, _label
+_start:
+  ret
+_label:
+  ret
diff --git a/test/ELF/linkerscript/exclude-multiple.s b/test/ELF/linkerscript/exclude-multiple.s
new file mode 100644 (file)
index 0000000..46ec18c
--- /dev/null
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/exclude-multiple1.s -o %tfile2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/exclude-multiple2.s -o %tfile3.o
+# RUN: echo "SECTIONS { \
+# RUN:   .foo : { *(.foo.1 EXCLUDE_FILE (*file1.o) .foo.2 EXCLUDE_FILE (*file2.o) .foo.3) } \
+# RUN:  }" > %t1.script
+# RUN: ld.lld -script %t1.script %tfile1.o %tfile2.o %tfile3.o -o %t1.o
+# RUN: llvm-objdump -s %t1.o | FileCheck %s
+
+# CHECK:      Contents of section .foo:
+# CHECK-NEXT:  01000000 00000000 04000000 00000000
+# CHECK-NEXT:  07000000 00000000 05000000 00000000
+# CHECK-NEXT:  08000000 00000000 03000000 00000000
+# CHECK-NEXT:  09000000 00000000
+# CHECK-NEXT: Contents of section .foo.2:
+# CHECK-NEXT:  02000000 00000000
+# CHECK-NEXT: Contents of section .foo.3:
+# CHECK-NEXT:  06000000 00000000
+
+# RUN: echo "SECTIONS { .foo : { *(EXCLUDE_FILE (*file1.o) EXCLUDE_FILE (*file2.o) .foo.3) } }" > %t2.script
+# RUN: not ld.lld -script %t2.script %tfile1.o %tfile2.o %tfile3.o -o %t2.o 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ERR
+# ERR: section pattern is expected
+
+# RUN: echo "SECTIONS { .foo : { *(EXCLUDE_FILE (*file1.o)) } }" > %t3.script
+# RUN: not ld.lld -script %t3.script %tfile1.o %tfile2.o %tfile3.o -o %t2.o 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=ERR
+
+.section .foo.1,"a"
+ .quad 1
+
+.section .foo.2,"a"
+ .quad 2
+
+.section .foo.3,"a"
+ .quad 3
diff --git a/test/ELF/linkerscript/excludefile.s b/test/ELF/linkerscript/excludefile.s
new file mode 100644 (file)
index 0000000..95b9534
--- /dev/null
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/include.s -o %t2
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/notinclude.s -o %t3.notinclude
+
+# RUN: echo "SECTIONS {} " > %t.script
+# RUN: ld.lld -o %t --script %t.script %t1 %t2 %t3.notinclude
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK: _start:
+# CHECK-NEXT: :       48 c7 c0 3c 00 00 00    movq    $60, %rax
+# CHECK-NEXT: :       48 c7 c7 2a 00 00 00    movq    $42, %rdi
+# CHECK-NEXT: :       cc      int3
+# CHECK-NEXT: :       cc      int3
+# CHECK: _potato:
+# CHECK-NEXT: :       90      nop
+# CHECK-NEXT: :       90      nop
+# CHECK-NEXT: :       cc      int3
+# CHECK-NEXT: :       cc      int3
+# CHECK: tomato:
+# CHECK-NEXT: :       b8 01 00 00 00  movl    $1, %eax
+
+# RUN: echo "SECTIONS { .patatino : \
+# RUN: { KEEP(*(EXCLUDE_FILE(*notinclude) .text)) } }" \
+# RUN:  > %t.script
+# RUN: ld.lld -o %t4 --script %t.script %t1 %t2 %t3.notinclude
+# RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=EXCLUDE
+
+# EXCLUDE: Disassembly of section .patatino:
+# EXCLUDE: _start:
+# EXCLUDE-NEXT: :       48 c7 c0 3c 00 00 00    movq    $60, %rax
+# EXCLUDE-NEXT: :       48 c7 c7 2a 00 00 00    movq    $42, %rdi
+# EXCLUDE-NEXT: :       cc      int3
+# EXCLUDE-NEXT: :       cc      int3
+# EXCLUDE: _potato:
+# EXCLUDE-NEXT: :       90      nop
+# EXCLUDE-NEXT: :       90      nop
+# EXCLUDE: Disassembly of section .text:
+# EXCLUDE: tomato:
+# EXCLUDE-NEXT: :       b8 01 00 00 00  movl    $1, %eax
+
+.section .text
+.globl _start
+_start:
+    mov $60, %rax
+    mov $42, %rdi
diff --git a/test/ELF/linkerscript/exidx-crash.s b/test/ELF/linkerscript/exidx-crash.s
new file mode 100644 (file)
index 0000000..c29d013
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: aarch64
+
+# We used to crash on this.
+
+# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux
+# RUN: echo "SECTIONS { .ARM.exidx : { *(.foo) } }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t
diff --git a/test/ELF/linkerscript/expr-invalid-sec.s b/test/ELF/linkerscript/expr-invalid-sec.s
new file mode 100644 (file)
index 0000000..5687751
--- /dev/null
@@ -0,0 +1,6 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { foo = ADDR(.text) + ADDR(.text); };" > %t.script
+# RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}.script:1: at least one side of the expression must be absolute
diff --git a/test/ELF/linkerscript/expr-sections.s b/test/ELF/linkerscript/expr-sections.s
new file mode 100644 (file)
index 0000000..eb60009
--- /dev/null
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:        . = . + 4; \
+# RUN:        .text : { \
+# RUN:          *(.text) \
+# RUN:          foo1 = ADDR(.text) + 1; bar1 = 1 + ADDR(.text); \
+# RUN:          foo2 = ADDR(.text) & 1; bar2 = 1 & ADDR(.text); \
+# RUN:          foo3 = ADDR(.text) | 1; bar3 = 1 | ADDR(.text); \
+# RUN:        } \
+# RUN: };" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-objdump -t -h %t.so | FileCheck %s
+
+# CHECK:  1 .text         00000000 0000000000000004 TEXT DATA
+
+# CHECK: 0000000000000005         .text                 00000000 foo1
+# CHECK: 0000000000000005         .text                 00000000 bar1
+# CHECK: 0000000000000000         .text                 00000000 foo2
+# CHECK: 0000000000000000         .text                 00000000 bar2
+# CHECK: 0000000000000005         .text                 00000000 foo3
+# CHECK: 0000000000000005         .text                 00000000 bar3
diff --git a/test/ELF/linkerscript/extend-pt-load.s b/test/ELF/linkerscript/extend-pt-load.s
new file mode 100644 (file)
index 0000000..f9a77c8
--- /dev/null
@@ -0,0 +1,69 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# This test demonstrates an odd consequence of the way we handle sections with just symbol
+# assignments.
+
+# First, run a test with no such section.
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN: .dynsym : {  } \
+# RUN: .hash : {  } \
+# RUN: .dynstr : {  } \
+# RUN:  .text : { *(.text) } \
+# RUN:  . = ALIGN(0x1000); \
+# RUN:  .data.rel.ro : { *(.data.rel.ro) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck --check-prefix=CHECK1 %s
+
+# CHECK1:      .text        PROGBITS 00000000000001bc 0001bc 000001 00 AX
+# CHECK1-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+
+# CHECK1:      LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E
+# CHECK1-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
+
+# Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now
+# cover the padding bits created by ALIGN.
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN: .dynsym : {  } \
+# RUN: .hash : {  } \
+# RUN: .dynstr : {  } \
+# RUN:  .text : { *(.text) } \
+# RUN:  . = ALIGN(0x1000); \
+# RUN:  bar : { HIDDEN(bar_sym = .); } \
+# RUN:  .data.rel.ro : { *(.data.rel.ro) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck --check-prefix=CHECK2 %s
+
+# CHECK2:      .text        PROGBITS 00000000000001bc 0001bc 000001 00 AX
+# CHECK2-NEXT: bar          PROGBITS 0000000000001000 001000 000000 00 AX
+# CHECK2-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA
+
+# CHECK2:      LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001000 0x001000 R E
+# CHECK2-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
+
+# If the current behavior becomes a problem we should consider just moving the commands out
+# of the section. That is, handle the above like the following test.
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN: .dynsym : {  } \
+# RUN: .hash : {  } \
+# RUN: .dynstr : {  } \
+# RUN:  .text : { *(.text) } \
+# RUN:  . = ALIGN(0x1000); \
+# RUN:  HIDDEN(bar_sym = .); \
+# RUN:  .data.rel.ro : { *(.data.rel.ro) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t3 --script %t.script %t.o -shared
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK1 %s
+
+nop
+
+.section .data.rel.ro, "aw"
+.byte 0
diff --git a/test/ELF/linkerscript/filename-spec.s b/test/ELF/linkerscript/filename-spec.s
new file mode 100644 (file)
index 0000000..d4bc495
--- /dev/null
@@ -0,0 +1,59 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfirst.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/filename-spec.s -o %tsecond.o
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   KEEP(*first.o(.foo)) \
+# RUN:   KEEP(*second.o(.foo)) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTSECOND %s
+# FIRSTSECOND:      Contents of section .foo:
+# FIRSTSECOND-NEXT:   01000000 00000000 11000000 00000000
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   KEEP(*second.o(.foo)) \
+# RUN:   KEEP(*first.o(.foo)) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SECONDFIRST %s
+# SECONDFIRST:      Contents of section .foo:
+# SECONDFIRST-NEXT:   11000000 00000000 01000000 00000000
+
+## Now the same tests but without KEEP. Checking that file name inside
+## KEEP is parsed fine.
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   *first.o(.foo) \
+# RUN:   *second.o(.foo) } }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTSECOND %s
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   *second.o(.foo) \
+# RUN:   *first.o(.foo) } }" > %t4.script
+# RUN: ld.lld -o %t4 --script %t4.script %tfirst.o %tsecond.o
+# RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=SECONDFIRST %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %T/filename-spec1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/filename-spec.s -o %T/filename-spec2.o
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   filename-spec2.o(.foo) \
+# RUN:   filename-spec1.o(.foo) } }" > %t5.script
+# RUN: ld.lld -o %t5 --script %t5.script \
+# RUN:   %T/filename-spec1.o %T/filename-spec2.o
+# RUN: llvm-objdump -s %t5 | FileCheck --check-prefix=SECONDFIRST %s
+
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:   filename-spec1.o(.foo) \
+# RUN:   filename-spec2.o(.foo) } }" > %t6.script
+# RUN: ld.lld -o %t6 --script %t6.script \
+# RUN:   %T/filename-spec1.o %T/filename-spec2.o
+# RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTSECOND %s
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 1
diff --git a/test/ELF/linkerscript/fill-exec-sections.s b/test/ELF/linkerscript/fill-exec-sections.s
new file mode 100644 (file)
index 0000000..f61d6da
--- /dev/null
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check that padding of executable sections are filled with trap bytes if not
+## otherwise specified in the script.
+# RUN: echo "SECTIONS { .exec : { *(.exec*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck %s --check-prefix=EXEC
+# EXEC:      0000 66cccccc cccccccc cccccccc cccccccc
+# EXEC-NEXT: 0010 66
+
+## Check that a fill expression or command overrides the default filler...
+# RUN: echo "SECTIONS { .exec : { *(.exec*) }=0x11223344 }" > %t2.script
+# RUN: ld.lld -o %t2.out --script %t2.script %t
+# RUN: llvm-objdump -s %t2.out | FileCheck %s --check-prefix=OVERRIDE
+# RUN: echo "SECTIONS { .exec : { FILL(0x11223344); *(.exec*) } }" > %t3.script
+# RUN: ld.lld -o %t3.out --script %t3.script %t
+# RUN: llvm-objdump -s %t3.out | FileCheck %s --check-prefix=OVERRIDE
+# OVERRIDE:      Contents of section .exec:
+# OVERRIDE-NEXT:  0000 66112233 44112233 44112233 44112233
+# OVERRIDE-NEXT:  0010 66
+
+## ...even for a value of zero.
+# RUN: echo "SECTIONS { .exec : { *(.exec*) }=0x00000000 }" > %t4.script
+# RUN: ld.lld -o %t4.out --script %t4.script %t
+# RUN: llvm-objdump -s %t4.out | FileCheck %s --check-prefix=ZERO
+# RUN: echo "SECTIONS { .exec : { FILL(0x00000000); *(.exec*) } }" > %t5.script
+# RUN: ld.lld -o %t5.out --script %t5.script %t
+# RUN: llvm-objdump -s %t5.out | FileCheck %s --check-prefix=ZERO
+# ZERO:      Contents of section .exec:
+# ZERO-NEXT:  0000 66000000 00000000 00000000 00000000
+# ZERO-NEXT:  0010 66
+
+.section        .exec.1,"ax"
+.align  16
+.byte   0x66
+
+.section        .exec.2,"ax"
+.align  16
+.byte   0x66
diff --git a/test/ELF/linkerscript/fill.s b/test/ELF/linkerscript/fill.s
new file mode 100644 (file)
index 0000000..6045060
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS {     \
+# RUN:  .out : {            \
+# RUN:   FILL(0x11111111)   \
+# RUN:   . += 2;            \
+# RUN:   *(.aaa)            \
+# RUN:   . += 4;            \
+# RUN:   *(.bbb)            \
+# RUN:   . += 4;            \
+# RUN:   FILL(0x22222222);  \
+# RUN:   . += 4;            \
+# RUN:  }                   \
+# RUN: }; " > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK:      Contents of section .out:
+# CHECK-NEXT: 2222aa22 222222bb 22222222 22222222
+
+.text
+.globl _start
+_start:
+
+.section .aaa, "a"
+.align 1
+.byte 0xAA
+
+.section .bbb, "a"
+.align 1
+.byte 0xBB
diff --git a/test/ELF/linkerscript/got-write-offset.s b/test/ELF/linkerscript/got-write-offset.s
new file mode 100644 (file)
index 0000000..323da7b
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux-gnu %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:   .data 0x1000 : { *(.data) } \
+# RUN:   .got 0x2000 : { \
+# RUN:     LONG(0) \
+# RUN:     *(.got) \
+# RUN:   } \
+# RUN:  };" > %t.script
+# RUN: ld.lld -shared -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck %s
+.text
+.global foo
+foo:
+       movl bar@GOT, %eax
+.data
+.local bar
+bar:
+       .zero 4
+# CHECK:      Contents of section .data:
+# CHECK-NEXT:  1000 00000000
+# CHECK:      Contents of section .got:
+# CHECK-NEXT:  2000 00000000 00100000
diff --git a/test/ELF/linkerscript/group.s b/test/ELF/linkerscript/group.s
new file mode 100644 (file)
index 0000000..53a1c89
--- /dev/null
@@ -0,0 +1,56 @@
+# REQUIRES: x86
+
+# RUN: mkdir -p %t.dir
+# RUN: rm -f %t.dir/libxyz.a
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/libsearch-st.s -o %t2.o
+# RUN: llvm-ar rcs %t.dir/libxyz.a %t2.o
+
+# RUN: echo "GROUP(\"%t\")" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "INPUT(\"%t\")" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script 2>/dev/null
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" =libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script  2>/dev/null
+# RUN: ld.lld -o %t2 %t.script --sysroot=%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" -lxyz )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script  2>/dev/null
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" libxyz.a )" > %t.script
+# RUN: not ld.lld -o %t2 %t.script  2>/dev/null
+# RUN: ld.lld -o %t2 %t.script -L%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t\" /libxyz.a )" > %t.script
+# RUN: echo "GROUP(\"%t\" /libxyz.a )" > %t.dir/xyz.script
+# RUN: not ld.lld -o %t2 %t.script 2>/dev/null
+# RUN: not ld.lld -o %t2 %t.script --sysroot=%t.dir  2>/dev/null
+# RUN: ld.lld -o %t2 %t.dir/xyz.script --sysroot=%t.dir
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(\"%t.script2\")" > %t.script1
+# RUN: echo "GROUP(\"%t\")" > %t.script2
+# RUN: ld.lld -o %t2 %t.script1
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "GROUP(AS_NEEDED(\"%t\"))" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/linkerscript/header-addr.s b/test/ELF/linkerscript/header-addr.s
new file mode 100644 (file)
index 0000000..f37d319
--- /dev/null
@@ -0,0 +1,47 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "PHDRS {all PT_LOAD PHDRS;} \
+# RUN:       SECTIONS { \
+# RUN:       . = 0x2000; \
+# RUN:       .text : {*(.text)} :all \
+# RUN:     }" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-readobj -program-headers %t.so | FileCheck %s
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x1040
+# CHECK-NEXT:     PhysicalAddress: 0x1040
+# CHECK-NEXT:     FileSize: 4176
+# CHECK-NEXT:     MemSize: 4176
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:       PF_W (0x2)
+# CHECK-NEXT:       PF_X (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 4096
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# RUN: ld.lld -o %t2.so --script %t.script %t.o -shared -z max-page-size=0x2000
+# RUN: llvm-readobj -program-headers %t2.so \
+# RUN:   | FileCheck --check-prefix=MAXPAGE %s
+
+# MAXPAGE:      ProgramHeaders [
+# MAXPAGE-NEXT:   ProgramHeader {
+# MAXPAGE-NEXT:     Type: PT_LOAD
+# MAXPAGE-NEXT:     Offset: 0x40
+# MAXPAGE-NEXT:     VirtualAddress: 0x40
+# MAXPAGE-NEXT:     PhysicalAddress: 0x40
+# MAXPAGE-NEXT:     FileSize: 8272
+# MAXPAGE-NEXT:     MemSize: 8272
+# MAXPAGE-NEXT:     Flags [
+# MAXPAGE-NEXT:       PF_R
+# MAXPAGE-NEXT:       PF_W
+# MAXPAGE-NEXT:       PF_X
+# MAXPAGE-NEXT:     ]
+# MAXPAGE-NEXT:     Alignment: 8192
+# MAXPAGE-NEXT:   }
+# MAXPAGE-NEXT: ]
diff --git a/test/ELF/linkerscript/huge-temporary-file.s b/test/ELF/linkerscript/huge-temporary-file.s
new file mode 100644 (file)
index 0000000..d58709c
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { .text 0x2000 : {. = 0x10 ; *(.text) } }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t1
+
+## This inputs previously created a 4gb temporarily fine under 32 bit
+## configuration. Issue was fixed. There is no clean way to check that from here.
+## This testcase added for documentation purposes.
+
+.globl _start
+_start:
+nop
diff --git a/test/ELF/linkerscript/implicit-program-header.s b/test/ELF/linkerscript/implicit-program-header.s
new file mode 100644 (file)
index 0000000..9598a6a
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t1 --script %S/Inputs/implicit-program-header.script  \
+# RUN:   %t.o -shared
+# RUN: llvm-readobj -elf-output-style=GNU -l %t1 | FileCheck %s
+
+# CHECK:      Segment Sections...
+# CHECK-NEXT:   00     .text .dynsym .hash .dynstr .dynamic
+# CHECK-NEXT:   01     .foo
+
+.quad 0
+.section .foo,"ax"
+.quad 0
diff --git a/test/ELF/linkerscript/input-order.s b/test/ELF/linkerscript/input-order.s
new file mode 100644 (file)
index 0000000..cb9ea35
--- /dev/null
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# This test case should place input sections in script order:
+# .foo.1 .foo.2 .bar.1 .bar.2
+# RUN: echo "SECTIONS { . = 0x1000; .foo : {*(.foo.*) *(.bar.*)  } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section=.foo -s %t1 | FileCheck --check-prefix=SCRIPT_ORDER %s
+# SCRIPT_ORDER: Contents of section .foo:
+# SCRIPT_ORDER-NEXT: 1000 00000000 00000000 ffffffff eeeeeeee
+
+# This test case should place input sections in native order:
+# .bar.1 .foo.1 .bar.2 .foo.2
+# RUN: echo "SECTIONS { . = 0x1000; .foo : {*(.foo.* .bar.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section=.foo -s %t1 | FileCheck --check-prefix=FILE_ORDER %s
+# FILE_ORDER: Contents of section .foo:
+# FILE_ORDER-NEXT: 1000 ffffffff 00000000 eeeeeeee 00000000
+
+.global _start
+_start:
+ nop
+
+.section .bar.1,"a"
+bar1:
+ .long 0xFFFFFFFF
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .bar.2,"a"
+bar2:
+ .long 0xEEEEEEEE
+
+.section .foo.2,"a"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/input-sec-dup.s b/test/ELF/linkerscript/input-sec-dup.s
new file mode 100644 (file)
index 0000000..fd88939
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.foo : { *(.foo) *(.foo) } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size
+# CHECK-NEXT:   0               00000000
+# CHECK-NEXT:   1 .foo          00000004
+# CHECK-NEXT:   2 .text         00000001
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .long 0
diff --git a/test/ELF/linkerscript/lazy-symbols.s b/test/ELF/linkerscript/lazy-symbols.s
new file mode 100644 (file)
index 0000000..22dffee
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/lazy-symbols.s -o %t1
+# RUN: llvm-ar rcs %tar %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2
+# RUN: echo "foo = 1;" > %t.script
+# RUN: ld.lld %t2 %tar --script %t.script -o %tout
+# RUN: llvm-readobj -symbols %tout | FileCheck %s
+
+# This test is to ensure a linker script can define a symbol which have the same
+# name as a lazy symbol.
+
+# CHECK: Name: foo
+# CHECK-NEXT: Value: 0x1
diff --git a/test/ELF/linkerscript/linkerscript.s b/test/ELF/linkerscript/linkerscript.s
new file mode 100644 (file)
index 0000000..cac902a
--- /dev/null
@@ -0,0 +1,54 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/libsearch-st.s -o %t2.o
+
+# RUN: echo "EXTERN( undef undef2 )" > %t.script
+# RUN: ld.lld %t -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "OUTPUT_FORMAT(elf64-x86-64) /*/*/ GROUP(\"%t\" )" > %t.script
+# RUN: ld.lld -o %t2 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: rm -f %t.out
+# RUN: echo "OUTPUT(\"%t.out\")" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo "SEARCH_DIR(/lib/foo/blah)" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo ";SEARCH_DIR(x);SEARCH_DIR(y);" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo ";" > %t.script
+# RUN: ld.lld %t.script %t
+# RUN: llvm-readobj %t.out > /dev/null
+
+# RUN: echo "INCLUDE \"%t.script2\" OUTPUT(\"%t.out\")" > %t.script1
+# RUN: echo "GROUP(\"%t\")" > %t.script2
+# RUN: ld.lld %t.script1
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "INCLUDE \"foo.script\"" > %t.script
+# RUN: echo "OUTPUT(\"%t.out\")" > %T/foo.script
+# RUN: not ld.lld %t.script > %t.log 2>&1
+# RUN: FileCheck -check-prefix=INCLUDE_ERR %s < %t.log
+# INCLUDE_ERR: error: {{.+}}.script:1: cannot open foo.script
+# INCLUDE_ERR-NEXT: error: {{.+}}.script:1: INCLUDE "foo.script"
+# RUN: ld.lld -L %T %t.script %t
+
+# RUN: echo "FOO(BAR)" > %t.script
+# RUN: not ld.lld -o foo %t.script > %t.log 2>&1
+# RUN: FileCheck -check-prefix=ERR1 %s < %t.log
+
+# ERR1: unknown directive: FOO
+
+.globl _start, _label
+_start:
+  ret
+_label:
+  ret
diff --git a/test/ELF/linkerscript/loadaddr.s b/test/ELF/linkerscript/loadaddr.s
new file mode 100644 (file)
index 0000000..33c5f21
--- /dev/null
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x1000; \
+# RUN:  .aaa : AT(0x2000) { *(.aaa) } \
+# RUN:  .bbb : { *(.bbb) } \
+# RUN:  .ccc : AT(0x3000) { *(.ccc) } \
+# RUN:  .ddd : AT(0x4000) { *(.ddd) } \
+# RUN:  .text : { *(.text) } \
+# RUN:  aaa_lma = LOADADDR(.aaa);  \
+# RUN:  bbb_lma = LOADADDR(.bbb);  \
+# RUN:  ccc_lma = LOADADDR(.ccc);  \
+# RUN:  ddd_lma = LOADADDR(.ddd);  \
+# RUN:  txt_lma = LOADADDR(.text); \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-objdump -t %t2 | FileCheck %s
+# RUN: echo "SECTIONS { v = LOADADDR(.zzz); }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | FileCheck --check-prefix=ERROR %s
+
+# CHECK:      0000000000002000         *ABS*     00000000 aaa_lma
+# CHECK-NEXT: 0000000000002008         *ABS*     00000000 bbb_lma
+# CHECK-NEXT: 0000000000003000         *ABS*     00000000 ccc_lma
+# CHECK-NEXT: 0000000000004000         *ABS*     00000000 ddd_lma
+# CHECK-NEXT: 0000000000004008         *ABS*     00000000 txt_lma
+# ERROR: {{.*}}.script:1: undefined section .zzz
+
+.global _start
+_start:
+ nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
+
+.section .ddd, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/locationcountererr.s b/test/ELF/linkerscript/locationcountererr.s
new file mode 100644 (file)
index 0000000..113e102
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ".text 0x2000 : {. = 0x10 ; *(.text) } }" >> %t.script
+# RUN: not ld.lld %t --script %t.script -o %t1 2>&1 | FileCheck %s
+# CHECK: {{.*}}.script:2: unable to move location counter backward for: .text
+
+.globl _start
+_start:
+nop
diff --git a/test/ELF/linkerscript/locationcountererr2.s b/test/ELF/linkerscript/locationcountererr2.s
new file mode 100644 (file)
index 0000000..8968f67
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS {" > %t.script
+# RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script
+# RUN: ld.lld %t.o --script %t.script -o %t -shared
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+# CHECK: Idx Name   Size      Address
+# CHECK:  1 .text 00000000 0000000000000010
+
+# RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script
+# RUN: ld.lld %t.o --script %t2.script -o %t -shared
diff --git a/test/ELF/linkerscript/memory.s b/test/ELF/linkerscript/memory.s
new file mode 100644 (file)
index 0000000..774a6f9
--- /dev/null
@@ -0,0 +1,114 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check simple RAM-only memory region.
+
+# RUN: echo "MEMORY { ram (rwx) : ORIGIN = 0x8000, LENGTH = 256K } \
+# RUN: SECTIONS { \
+# RUN:   .text : { *(.text) } > ram \
+# RUN:   .data : { *(.data) } > ram \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=RAM %s
+
+# RAM:       1 .text         00000001 0000000000008000 TEXT DATA
+# RAM-NEXT:  2 .data         00001000 0000000000008001 DATA
+
+## Check RAM and ROM memory regions.
+
+# RUN: echo "MEMORY { \
+# RUN:   ram (rwx) : ORIGIN = 0, LENGTH = 1024M \
+# RUN:   rom (rx) : org = (0x80 * 0x1000 * 0x1000), len = 64M \
+# RUN: } \
+# RUN: SECTIONS { \
+# RUN:   .text : { *(.text) } > rom \
+# RUN:   .data : { *(.data) } > ram \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=RAMROM %s
+
+# RAMROM:       1 .text         00000001 0000000080000000 TEXT DATA
+# RAMROM-NEXT:  2 .data         00001000 0000000000000000 DATA
+
+## Check memory region placement by attributes.
+
+# RUN: echo "MEMORY { \
+# RUN:   ram (!rx) : ORIGIN = 0, LENGTH = 1024M \
+# RUN:   rom (rx) : o = 0x80000000, l = 64M \
+# RUN: } \
+# RUN: SECTIONS { \
+# RUN:   .text : { *(.text) } \
+# RUN:   .data : { *(.data) } > ram \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=ATTRS %s
+
+# ATTRS:  1 .text         00000001 0000000080000000 TEXT DATA
+# ATTRS:  2 .data         00001000 0000000000000000 DATA
+
+## Check bad `ORIGIN`.
+
+# RUN: echo "MEMORY { ram (rwx) : XYZ = 0x8000 } }" > %t.script
+# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR1 %s
+# ERR1: {{.*}}.script:1: expected one of: ORIGIN, org, or o
+
+## Check bad `LENGTH`.
+
+# RUN: echo "MEMORY { ram (rwx) : ORIGIN = 0x8000, XYZ = 256K } }" > %t.script
+# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR2 %s
+# ERR2: {{.*}}.script:1: expected one of: LENGTH, len, or l
+
+## Check duplicate regions.
+
+# RUN: echo "MEMORY { ram (rwx) : o = 8, l = 256K ram (rx) : o = 0, l = 256K }" > %t.script
+# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR3 %s
+# ERR3: {{.*}}.script:1: region 'ram' already defined
+
+## Check no region available.
+
+# RUN: echo "MEMORY { ram (!rx) : ORIGIN = 0x8000, LENGTH = 256K } \
+# RUN: SECTIONS { \
+# RUN:   .text : { *(.text) } \
+# RUN:   .data : { *(.data) } > ram \
+# RUN: }" > %t.script
+# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR4 %s
+# ERR4: {{.*}}: no memory region specified for section '.text'
+
+## Check undeclared region.
+
+# RUN: echo "SECTIONS { .text : { *(.text) } > ram }" > %t.script
+# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR5 %s
+# ERR5: {{.*}}: memory region 'ram' not declared
+
+## Check region overflow.
+
+# RUN: echo "MEMORY { ram (rwx) : ORIGIN = 0, LENGTH = 2K } \
+# RUN: SECTIONS { \
+# RUN:   .text : { *(.text) } > ram \
+# RUN:   .data : { *(.data) } > ram \
+# RUN: }" > %t.script
+# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR6 %s
+# ERR6: {{.*}}: section '.data' will not fit in region 'ram': overflowed by 2049 bytes
+
+## Check invalid region attributes.
+
+# RUN: echo "MEMORY { ram (abc) : ORIGIN = 8000, LENGTH = 256K } }" > %t.script
+# RUN: not ld.lld -o %t2 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR7 %s
+# ERR7: {{.*}}.script:1: invalid memory region attribute
+
+.text
+.global _start
+_start:
+  nop
+
+.data
+b:
+  .long 1
+  .zero 4092
diff --git a/test/ELF/linkerscript/merge-sections-reloc.s b/test/ELF/linkerscript/merge-sections-reloc.s
new file mode 100644 (file)
index 0000000..6393415
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/merge-sections-reloc.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+## Check that sections content is not corrupted.
+# CHECK:      Contents of section .text:
+# CHECK-NEXT:  44332211 00000000 44332211 00000000
+# CHECK-NEXT:  f0ffffff ffffffff
+
+.globl _start
+_foo:
+ .quad 0x11223344
+ .quad _start - .
diff --git a/test/ELF/linkerscript/merge-sections-syms.s b/test/ELF/linkerscript/merge-sections-syms.s
new file mode 100644 (file)
index 0000000..713d334
--- /dev/null
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN:   . = SIZEOF_HEADERS; \
+# RUN:   .rodata : { *(.aaa) *(.bbb) A = .; *(.ccc) B = .; } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: A
+# CHECK-NEXT:     Value: 0x195
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: B
+# CHECK-NEXT:     Value: 0x196
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+
+.section .aaa,"a"
+.byte 11
+
+.section .bbb,"aMS",@progbits,1
+.asciz "foo"
+
+.section .ccc,"a"
+.byte 33
diff --git a/test/ELF/linkerscript/merge-sections.s b/test/ELF/linkerscript/merge-sections.s
new file mode 100644 (file)
index 0000000..950d822
--- /dev/null
@@ -0,0 +1,62 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:   . = SIZEOF_HEADERS; \
+# RUN:   .foo : { begin = .; *(.foo.*) end = .;} \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -s -t %t1 | FileCheck %s
+
+# CHECK:        Name: .foo
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:     SHF_STRINGS
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x[[ADDR1:.*]]
+# CHECK-NEXT:   Offset: 0x[[ADDR1]]
+# CHECK-NEXT:   Size: 14
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 2
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT: }
+
+# CHECK:      Name: begin
+# CHECK-NEXT: Value: 0x[[ADDR1]]
+
+# CHECK:      Name: end
+# 0x19E = begin + sizeof(.foo) = 0x190 + 0xE
+# CHECK-NEXT: Value: 0x19E
+
+# Check that we don't crash with --gc-sections
+# RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared
+# RUN: llvm-readobj -s -t %t2 | FileCheck %s --check-prefix=GC
+
+# GC:        Name: .foo
+# GC-NEXT:   Type: SHT_PROGBITS
+# GC-NEXT:   Flags [
+# GC-NEXT:     SHF_ALLOC
+# GC-NEXT:   ]
+
+.section        .foo.1a,"aMS",@progbits,1
+.asciz "foo"
+
+.section        .foo.1b,"aMS",@progbits,1
+.asciz "foo"
+
+.section        .foo.2a,"aM",@progbits,1
+.byte 42
+
+.section        .foo.2b,"aM",@progbits,1
+.byte 42
+
+.section        .foo.3a,"aM",@progbits,2
+.align 2
+.short 42
+
+.section        .foo.3b,"aM",@progbits,2
+.align 2
+.short 42
diff --git a/test/ELF/linkerscript/multi-sections-constraint.s b/test/ELF/linkerscript/multi-sections-constraint.s
new file mode 100644 (file)
index 0000000..bfedd10
--- /dev/null
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  .text : { *(.text) } \
+# RUN:  . = 0x1000; .aaa : ONLY_IF_RO { *(.aaa.*) } \
+# RUN:  . = 0x2000; .aaa : ONLY_IF_RW { *(.aaa.*) } } " > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK: .aaa          00000010 0000000000002000 DATA
+
+
+# RUN: echo "SECTIONS { \
+# RUN:  .text : { *(.text) } \
+# RUN:  . = 0x1000; .aaa : ONLY_IF_RW { *(.aaa.*) } \
+# RUN:  . = 0x2000; .aaa : ONLY_IF_RO { *(.aaa.*) } } " > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=REV
+
+# REV:      Sections:
+# REV-NEXT: Idx Name          Size      Address          Type
+# REV:  .aaa          00000010 0000000000001000 DATA
+
+.global _start
+_start:
+ nop
+
+.section .aaa.1, "aw"
+.quad 1
+
+.section .aaa.2, "aw"
+.quad 1
diff --git a/test/ELF/linkerscript/multiple-tbss.s b/test/ELF/linkerscript/multiple-tbss.s
new file mode 100644 (file)
index 0000000..6bbbca9
--- /dev/null
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t
+# RUN: llvm-readobj -l -s %t | FileCheck %s
+
+# CHECK:        Name: .tbss
+# CHECK-NEXT:   Type: SHT_NOBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_TLS
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 8
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: foo
+# CHECK-NEXT:   Type: SHT_NOBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_TLS
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 1
+
+# CHECK:      Type: PT_TLS
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: VirtualAddress:
+# CHECK-NEXT: PhysicalAddress:
+# CHECK-NEXT: FileSize: 0
+# CHECK-NEXT: MemSize: 9
+
+.section        .tbss,"awT",@nobits
+.quad   0
+.section        foo,"awT",@nobits
+.byte 0
diff --git a/test/ELF/linkerscript/no-pt-load.s b/test/ELF/linkerscript/no-pt-load.s
new file mode 100644 (file)
index 0000000..c704025
--- /dev/null
@@ -0,0 +1,5 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "PHDRS {foo PT_DYNAMIC ;} " \
+# RUN:      "SECTIONS { .text : { *(.text) } : foo }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t.o
diff --git a/test/ELF/linkerscript/no-space.s b/test/ELF/linkerscript/no-space.s
new file mode 100644 (file)
index 0000000..fc9e5b1
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS {foo 0 : {*(foo*)} }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
+
+# RUN: echo "SECTIONS {foo : {*(foo*)} }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s
+
+# There is not enough address space available for the header, so just start the PT_LOAD
+# after it. Don't create a PT_PHDR as the header is not allocated.
+
+# CHECK: Program Headers:
+# CHECK-NEXT: Type  Offset   VirtAddr           PhysAddr
+# CHECK-NEXT: LOAD  0x001000 0x0000000000000000 0x0000000000000000
+
+# CHECK:      Section to Segment mapping:
+# CHECK-NEXT:  Segment Sections...
+# CHECK-NEXT:   00     foo .text .dynsym .hash .dynstr
+
+.section foo, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/noload.s b/test/ELF/linkerscript/noload.s
new file mode 100644 (file)
index 0000000..9d0e085
--- /dev/null
@@ -0,0 +1,46 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:        .data_noload_a (NOLOAD) : { *(.data_noload_a) } \
+# RUN:        .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } };" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj --symbols -sections %t
+
+# CHECK:      Section {
+# CHECK-NEXT:   Index: 2
+# CHECK-NEXT:   Name: .data_noload_a
+# CHECK-NEXT:   Type: SHT_NOBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x0
+# CHECK-NEXT:   Offset: 0x1000
+# CHECK-NEXT:   Size: 4096
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 3
+# CHECK-NEXT:   Name: .data_noload_b
+# CHECK-NEXT:   Type: SHT_NOBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x10000
+# CHECK-NEXT:   Offset: 0x1000
+# CHECK-NEXT:   Size: 4096
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT: }
+
+.section .data_noload_a,"aw",@progbits
+.zero 4096
+
+.section .data_noload_b,"aw",@progbits
+.zero 4096
diff --git a/test/ELF/linkerscript/non-absolute.s b/test/ELF/linkerscript/non-absolute.s
new file mode 100644 (file)
index 0000000..a0e9e7d
--- /dev/null
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: echo "SECTIONS { A = . - 0x10; B = A + 0x1; }" > %t.script
+# RUN: ld.lld -shared %t1.o --script %t.script -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DUMP
+# RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SYMBOL
+
+# DUMP:       Disassembly of section .text:
+# DUMP-NEXT:  foo:
+# DUMP-NEXT:   0: {{.*}} -21(%rip), %eax
+
+# SYMBOL:     Symbol {
+# SYMBOL:        Name: B
+# SYMBOL-NEXT:   Value: 0xFFFFFFFFFFFFFFF1
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Local
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other [
+# SYMBOL-NEXT:     STV_HIDDEN
+# SYMBOL-NEXT:   ]
+# SYMBOL-NEXT:   Section: .text
+# SYMBOL-NEXT: }
+
+.text
+.globl foo
+.type foo, @function
+foo:
+ movl B(%rip), %eax
+
+.hidden B
diff --git a/test/ELF/linkerscript/non-absolute2.s b/test/ELF/linkerscript/non-absolute2.s
new file mode 100644 (file)
index 0000000..97c34d3
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: echo "SECTIONS { A = . + 0x1; . += 0x1000; }" > %t.script
+# RUN: ld.lld -shared %t1.o --script %t.script -o %t
+# RUN: llvm-objdump -section-headers -t %t | FileCheck %s
+
+# CHECK:       Sections:
+# CHECK-NEXT:   Idx Name          Size      Address
+# CHECK-NEXT:    0               00000000 0000000000000000
+# CHECK-NEXT:    1 .text         00000000 0000000000001000
+
+# CHECK: 0000000000000001         .text            00000000 A
diff --git a/test/ELF/linkerscript/non-alloc-segment.s b/test/ELF/linkerscript/non-alloc-segment.s
new file mode 100644 (file)
index 0000000..229f028
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+################################################################################
+## Test that non-alloc section .foo can be assigned to a segment. Check that
+## the values of the offset and file size of this segment's PHDR are correct.
+##
+## This functionality allows non-alloc metadata, which is not required at
+## run-time, to be added to a custom segment in a file. This metadata may be
+## read/edited by tools/loader using the values of the offset and file size from
+## the custom segment's PHDR. This is particularly important if section headers
+## have been stripped.
+# RUN: echo "PHDRS {text PT_LOAD; foo 0x12345678;} \
+# RUN:       SECTIONS { \
+# RUN:           .text : {*(.text .text*)} :text \
+# RUN:           .foo : {*(.foo)} :foo \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s
+# RUN: llvm-readobj -l %t | FileCheck --check-prefix=PHDR %s
+
+# CHECK: Program Headers:
+# CHECK-NEXT:  Type
+# CHECK-NEXT:  LOAD
+# CHECK-NEXT:  <unknown>: 0x12345678
+
+# CHECK:      Section to Segment mapping:
+# CHECK-NEXT:  Segment Sections...
+# CHECK-NEXT:   00     .text
+# CHECK-NEXT:   01     .foo
+
+# PHDR: Type:  (0x12345678)
+# PHDR-NEXT: Offset: 0x1004
+# PHDR-NEXT: VirtualAddress
+# PHDR-NEXT: PhysicalAddress
+# PHDR-NEXT: FileSize: 4
+
+.global _start
+_start:
+ nop
+
+.section .foo
+ .align 4
+ .long 0
diff --git a/test/ELF/linkerscript/non-alloc.s b/test/ELF/linkerscript/non-alloc.s
new file mode 100644 (file)
index 0000000..861c749
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+
+# RUN: echo "SECTIONS { .foo 0 : {*(foo)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -elf-output-style=GNU -s -l %t1 | FileCheck %s
+
+# Test that we create all necessary PT_LOAD. We use to stop at the first
+# non-alloc, causing us to not create PT_LOAD for linker generated sections.
+
+# CHECK: Program Headers:
+# CHECK-NEXT:  Type
+# CHECK-NEXT:  LOAD {{.*}} R E
+# CHECK-NEXT:  LOAD {{.*}} RW
+
+# CHECK:      Section to Segment mapping:
+# CHECK-NEXT:  Segment Sections...
+# CHECK-NEXT:   00     .text .dynsym .hash .dynstr
+# CHECK-NEXT:   01     .dynamic
+
+nop
+.section foo
+.quad 0
diff --git a/test/ELF/linkerscript/numbers.s b/test/ELF/linkerscript/numbers.s
new file mode 100644 (file)
index 0000000..d4fd13f
--- /dev/null
@@ -0,0 +1,80 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  . = 1000h;              \
+# RUN:  .hex1 : { *(.hex.1) }   \
+# RUN:  . = 1010H;              \
+# RUN:  .hex2 : { *(.hex.2) }   \
+# RUN:  . = 10k;                \
+# RUN:  .kilo1 : { *(.kilo.1) } \
+# RUN:  . = 11K;                \
+# RUN:  .kilo2 : { *(.kilo.2) } \
+# RUN:  . = 1m;                 \
+# RUN:  .mega1 : { *(.mega.1) } \
+# RUN:  . = 2M;                 \
+# RUN:  .mega2 : { *(.mega.2) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
+
+# CHECK:     Sections:
+# CHECK-NEXT: Idx Name          Size      Address
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .hex1         00000008 0000000000001000
+# CHECK-NEXT:   2 .hex2         00000008 0000000000001010
+# CHECK-NEXT:   3 .kilo1        00000008 0000000000002800
+# CHECK-NEXT:   4 .kilo2        00000008 0000000000002c00
+# CHECK-NEXT:   5 .mega1        00000008 0000000000100000
+# CHECK-NEXT:   6 .mega2        00000008 0000000000200000
+
+## Mailformed number errors.
+# RUN: echo "SECTIONS { . = 0x11h; }" > %t2.script
+# RUN: not ld.lld %t --script %t2.script -o %t3 2>&1 | \
+# RUN:  FileCheck --check-prefix=ERR1 %s
+# ERR1: malformed number: 0x11h
+
+# RUN: echo "SECTIONS { . = 0x11k; }" > %t3.script
+# RUN: not ld.lld %t --script %t3.script -o %t4 2>&1 | \
+# RUN:  FileCheck --check-prefix=ERR2 %s
+# ERR2: malformed number: 0x11k
+
+# RUN: echo "SECTIONS { . = 0x11m; }" > %t4.script
+# RUN: not ld.lld %t --script %t4.script -o %t5 2>&1 | \
+# RUN:  FileCheck --check-prefix=ERR3 %s
+# ERR3: malformed number: 0x11m
+
+## Make sure that numbers can be followed by a ":" with and without a space,
+## e.g. "0x100 :" or "0x100:"
+# RUN: echo "SECTIONS { \
+# RUN:  .hex1 0x400 : { *(.hex.1) } \
+# RUN:  .hex2 0x500:{ *(.hex.2) } \
+# RUN: }" > %t5.script
+# RUN: ld.lld %t --script %t5.script -o %t6
+# RUN: llvm-objdump -section-headers %t6 | FileCheck -check-prefix=SECADDR %s
+# SECADDR:     Sections:
+# SECADDR-NEXT: Idx Name          Size      Address
+# SECADDR-NEXT:   0               00000000 0000000000000000
+# SECADDR-NEXT:   1 .hex1         00000008 0000000000000400
+# SECADDR-NEXT:   2 .hex2         00000008 0000000000000500
+
+.globl _start
+_start:
+nop
+
+.section .hex.1, "a"
+.quad 0
+
+.section .kilo.1, "a"
+.quad 0
+
+.section .mega.1, "a"
+.quad 0
+
+.section .hex.2, "a"
+.quad 0
+
+.section .kilo.2, "a"
+.quad 0
+
+.section .mega.2, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/obj-symbol-value.s b/test/ELF/linkerscript/obj-symbol-value.s
new file mode 100644 (file)
index 0000000..1c0b119
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { foo = bar; .bar : { *(.bar*) } }" > %t.script
+# RUN: ld.lld %t.o --script %t.script -o %t.so -shared
+# RUN: llvm-readobj -t %t.so | FileCheck %s
+
+# CHECK:     Symbol {
+# CHECK:      Name: bar
+# CHECK-NEXT: Value: 0x[[VAL:.*]]
+# CHECK:      Name: foo
+# CHECK-NEXT: Value: 0x[[VAL]]
+
+.section .bar.1, "a"
+.quad 0
+
+.section .bar.2, "a"
+.quad 0
+.global bar
+bar:
diff --git a/test/ELF/linkerscript/openbsd-bootdata.s b/test/ELF/linkerscript/openbsd-bootdata.s
new file mode 100644 (file)
index 0000000..3e90574
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+# RUN: echo "PHDRS { boot PT_OPENBSD_BOOTDATA; }" > %t.script
+# RUN: ld.lld --script %t.script %t.o -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck %s
+
+# CHECK:      ProgramHeader {
+# CHECK:        Type: PT_OPENBSD_BOOTDATA (0x65A41BE6)
diff --git a/test/ELF/linkerscript/openbsd-randomize.s b/test/ELF/linkerscript/openbsd-randomize.s
new file mode 100644 (file)
index 0000000..bf885f4
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+# RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; rand PT_OPENBSD_RANDOMIZE; } \
+# RUN:       SECTIONS { . = SIZEOF_HEADERS; \
+# RUN:         .text : { *(.text) } \
+# RUN:         .openbsd.randomdata : { *(.openbsd.randomdata) } : rand }" > %t.script
+# RUN: ld.lld --script %t.script %t.o -o %t
+# RUN: llvm-readobj --program-headers -s %t | FileCheck %s
+
+# CHECK:      ProgramHeader {
+# CHECK:        Type: PT_OPENBSD_RANDOMIZE (0x65A3DBE6)
+# CHECK-NEXT:   Offset: 0x74
+# CHECK-NEXT:   VirtualAddress: 0x74
+# CHECK-NEXT:   PhysicalAddress: 0x74
+# CHECK-NEXT:   FileSize: 8
+# CHECK-NEXT:   MemSize: 8
+# CHECK-NEXT:   Flags [ (0x4)
+# CHECK-NEXT:     PF_R (0x4)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Alignment: 1
+# CHECK-NEXT: }
+
+.section .openbsd.randomdata, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/openbsd-wxneeded.s b/test/ELF/linkerscript/openbsd-wxneeded.s
new file mode 100644 (file)
index 0000000..d371da9
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+# RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; wxneeded PT_OPENBSD_WXNEEDED; }" > %t.script
+# RUN: ld.lld -z wxneeded --script %t.script %t.o -o %t
+# RUN: llvm-readobj --program-headers %t | FileCheck %s
+
+# CHECK:      ProgramHeader {
+# CHECK:        Type: PT_OPENBSD_WXNEEDED (0x65A3DBE7)
+# CHECK-NEXT:   Offset: 0x0
+# CHECK-NEXT:   VirtualAddress: 0x0
+# CHECK-NEXT:   PhysicalAddress: 0x0
+# CHECK-NEXT:   FileSize: 0
+# CHECK-NEXT:   MemSize: 0
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     PF_R
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Alignment: 0
+# CHECK-NEXT: }
diff --git a/test/ELF/linkerscript/operators.s b/test/ELF/linkerscript/operators.s
new file mode 100644 (file)
index 0000000..470558d
--- /dev/null
@@ -0,0 +1,93 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  plus = 1 + 2 + 3; \
+# RUN:  minus = 5 - 1; \
+# RUN:  div = 6 / 2; \
+# RUN:  mul = 1 + 2 * 3; \
+# RUN:  nospace = 1+2*6/3; \
+# RUN:  braces = 1 + (2 + 3) * 4; \
+# RUN:  and = 0xbb & 0xee; \
+# RUN:  ternary1 = 1 ? 1 : 2; \
+# RUN:  ternary2 = 0 ? 1 : 2; \
+# RUN:  less = 1 < 0 ? 1 : 2; \
+# RUN:  lesseq = 1 <= 1 ? 1 : 2; \
+# RUN:  greater = 0 > 1 ? 1 : 2; \
+# RUN:  greatereq = 1 >= 1 ? 1 : 2; \
+# RUN:  eq = 1 == 1 ? 1 : 2; \
+# RUN:  neq = 1 != 1 ? 1 : 2; \
+# RUN:  plusassign = 1; \
+# RUN:  plusassign += 2; \
+# RUN:  unary = -1 + 3; \
+# RUN:  lshift = 1 << 5; \
+# RUN:  rshift = 0xff >> 3; \
+# RUN:  maxpagesize = CONSTANT (MAXPAGESIZE); \
+# RUN:  commonpagesize = CONSTANT (COMMONPAGESIZE); \
+# RUN:  . = 0xfff0; \
+# RUN:  datasegmentalign = DATA_SEGMENT_ALIGN (0xffff, 0); \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-objdump -t %t2 | FileCheck %s
+
+# CHECK: 00000000000006 *ABS* 00000000 plus
+# CHECK: 00000000000004 *ABS* 00000000 minus
+# CHECK: 00000000000003 *ABS* 00000000 div
+# CHECK: 00000000000007 *ABS* 00000000 mul
+# CHECK: 00000000000005 *ABS* 00000000 nospace
+# CHECK: 00000000000015 *ABS* 00000000 braces
+# CHECK: 000000000000aa *ABS* 00000000 and
+# CHECK: 00000000000001 *ABS* 00000000 ternary1
+# CHECK: 00000000000002 *ABS* 00000000 ternary2
+# CHECK: 00000000000002 *ABS* 00000000 less
+# CHECK: 00000000000001 *ABS* 00000000 lesseq
+# CHECK: 00000000000002 *ABS* 00000000 greater
+# CHECK: 00000000000001 *ABS* 00000000 greatereq
+# CHECK: 00000000000001 *ABS* 00000000 eq
+# CHECK: 00000000000002 *ABS* 00000000 neq
+# CHECK: 00000000000003 *ABS* 00000000 plusassign
+# CHECK: 00000000000002 *ABS* 00000000 unary
+# CHECK: 00000000000020 *ABS* 00000000 lshift
+# CHECK: 0000000000001f *ABS* 00000000 rshift
+# CHECK: 00000000001000 *ABS* 00000000 maxpagesize
+# CHECK: 00000000001000 *ABS* 00000000 commonpagesize
+# CHECK: 0000000000ffff *ABS* 00000000 datasegmentalign
+
+## Mailformed number error.
+# RUN: echo "SECTIONS { . = 0x12Q41; }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=NUMERR %s
+# NUMERR: malformed number: 0x12Q41
+
+## Missing closing bracket.
+# RUN: echo "SECTIONS { . = (1; }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=BRACKETERR %s
+# BRACKETERR: ) expected, but got ;
+
+## Missing opening bracket.
+# RUN: echo "SECTIONS { . = 1); }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=BRACKETERR2 %s
+# BRACKETERR2: ; expected, but got )
+
+## Empty expression.
+# RUN: echo "SECTIONS { . = ; }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=ERREXPR %s
+# ERREXPR: malformed number: ;
+
+## Div by zero error.
+# RUN: echo "SECTIONS { . = 1 / 0; }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=DIVZERO %s
+# DIVZERO: division by zero
+
+## Broken ternary operator expression.
+# RUN: echo "SECTIONS { . = 1 ? 2; }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN:  FileCheck --check-prefix=TERNERR %s
+# TERNERR: : expected, but got ;
+
+.globl _start
+_start:
+nop
diff --git a/test/ELF/linkerscript/orphan-align.s b/test/ELF/linkerscript/orphan-align.s
new file mode 100644 (file)
index 0000000..edd637b
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:         . = SIZEOF_HEADERS; \
+# RUN:         .text : { *(.text) } \
+# RUN:         . = ALIGN(0x1000); \
+# RUN:         .data.rel.ro : { *(.data.rel.ro) } \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t -T %t.script %t.o -shared
+# RUN: llvm-readobj -l %t | FileCheck %s
+
+
+# Test that the orphan section foo is placed before the ALIGN and so the second
+# PT_LOAD is aligned.
+
+
+# CHECK:      Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x0
+
+# CHECK:      Type: PT_LOAD
+# CHECK-NEXT: Offset: 0x1000
+
+nop
+.section .data.rel.ro, "aw"
+.byte 0
+
+.section foo, "ax"
+nop
diff --git a/test/ELF/linkerscript/orphan-first-cmd.s b/test/ELF/linkerscript/orphan-first-cmd.s
new file mode 100644 (file)
index 0000000..263cb30
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:         foo = 123; \
+# RUN:         . = 0x1000; \
+# RUN:         . = 0x2000; \
+# RUN:         .bar : { *(.bar) } \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t -T %t.script %t.o -shared
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK:      Name: .text
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_ALLOC
+# CHECK-NEXT:   SHF_EXECINSTR
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x1000
+
+.section .bar, "aw"
diff --git a/test/ELF/linkerscript/orphan.s b/test/ELF/linkerscript/orphan.s
new file mode 100644 (file)
index 0000000..f510853
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS {       \
+# RUN:  .text : { *(.text) }  \
+# RUN:  .rw1 : { *(.rw1) }    \
+# RUN:  .rw2 : { *(.rw2) }    \
+# RUN:  .rw3 : { *(.rw3) }    \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+## .jcr is a relro section and should be placed after other RW sections.
+## .bss is SHT_NOBITS section and should be last RW section, so some space
+## in ELF file could be saved.
+# CHECK:       0               00000000 0000000000000000
+# CHECK-NEXT:  1 .text         00000000 0000000000000000 TEXT DATA
+# CHECK-NEXT:  2 .rw1          00000008 0000000000000000 DATA
+# CHECK-NEXT:  3 .rw2          00000008 0000000000000008 DATA
+# CHECK-NEXT:  4 .rw3          00000008 0000000000000010 DATA
+# CHECK-NEXT:  5 .jcr          00000008 0000000000000018 DATA
+# CHECK-NEXT:  6 .bss          00000008 0000000000000020 BSS
+
+.section .rw1, "aw"
+ .quad 0
+
+.section .rw2, "aw"
+ .quad 0
+
+.section .rw3, "aw"
+ .quad 0
+
+.section .jcr, "aw"
+ .quad 0
+
+.section .bss, "aw",@nobits
+ .quad 0
diff --git a/test/ELF/linkerscript/orphans.s b/test/ELF/linkerscript/orphans.s
new file mode 100644 (file)
index 0000000..0a8c7ab
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { .writable : { *(.writable) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=TEXTORPHAN %s
+
+# RUN: echo "SECTIONS { .text : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=WRITABLEORPHAN %s
+
+# TEXTORPHAN:      Sections:
+# TEXTORPHAN-NEXT: Idx Name
+# TEXTORPHAN-NEXT:   0
+# TEXTORPHAN-NEXT:   1 .text
+# TEXTORPHAN-NEXT:   2 .writable
+
+# WRITABLEORPHAN:      Sections:
+# WRITABLEORPHAN-NEXT: Idx Name
+# WRITABLEORPHAN-NEXT:   0
+# WRITABLEORPHAN-NEXT:   1 .text
+# WRITABLEORPHAN-NEXT:   2 .writable
+
+.global _start
+_start:
+ nop
+
+.section .writable,"aw"
+ .zero 4
diff --git a/test/ELF/linkerscript/ouputformat.s b/test/ELF/linkerscript/ouputformat.s
new file mode 100644 (file)
index 0000000..7d4402a
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: echo "OUTPUT_FORMAT(x, y, z)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: ld.lld -shared -o %t2 %t1 %t.script
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "OUTPUT_FORMAT(x, y)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: not ld.lld -shared -o %t2 %t1 %t.script
diff --git a/test/ELF/linkerscript/out-of-order.s b/test/ELF/linkerscript/out-of-order.s
new file mode 100644 (file)
index 0000000..6cfd533
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-linux %s -o %t.o
+# RUN: echo "SECTIONS { .data 0x4000 : { *(.data) } .text 0x2000 : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
+# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .data         00000008 0000000000004000  DATA
+# CHECK-NEXT:   2 .dynamic      00000060 0000000000004008
+# CHECK-NEXT:   3 .text         00000008 0000000000002000  TEXT DATA
+# CHECK-NEXT:   4 .dynsym       00000018 0000000000002008
+# CHECK-NEXT:   5 .hash         00000010 0000000000002020
+# CHECK-NEXT:   6 .dynstr       00000001 0000000000002030
+
+.quad 0
+.data
+.quad 0
diff --git a/test/ELF/linkerscript/output-too-large.s b/test/ELF/linkerscript/output-too-large.s
new file mode 100644 (file)
index 0000000..c892a88
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { . = 0xffffffff; *(.text*); } }" > %t.script
+# RUN: not ld.lld --script %t.script %t.o -o %t 2>&1 | FileCheck %s
+# CHECK: error: output file too large
+
+.global _start
+_start:
+  nop
diff --git a/test/ELF/linkerscript/outputarch.s b/test/ELF/linkerscript/outputarch.s
new file mode 100644 (file)
index 0000000..dd3bf93
--- /dev/null
@@ -0,0 +1,4 @@
+# REQUIRES: x86
+# RUN: echo "OUTPUT_ARCH(All data written here is ignored)" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
+# RUN: ld.lld -shared -o %t2 %t1 %t.script
diff --git a/test/ELF/linkerscript/outsections-addr.s b/test/ELF/linkerscript/outsections-addr.s
new file mode 100644 (file)
index 0000000..fda9bc9
--- /dev/null
@@ -0,0 +1,110 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:   .aaa 0x2000 : { *(.aaa) } \
+# RUN:   .bbb 0x1 ? 0x3000 : 0x4000 : { *(.bbb) } \
+# RUN:   .ccc ALIGN(CONSTANT(MAXPAGESIZE)) + (. & (CONSTANT(MAXPAGESIZE) - 1)) : { *(.ccc) } \
+# RUN:   .ddd 0x5001 : { *(.ddd) } \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %tout
+# RUN: llvm-readobj -s %tout | FileCheck %s
+
+## Check:
+## 1) Simple constant as address.
+## 2) That something that contains ":" character, like ternary
+##    operator works as expression.
+## 3) That complex expressions work.
+## 4) That section alignment still applied to explicitly specified address.
+
+#CHECK:Sections [
+#CHECK:  Section {
+#CHECK:    Index: 0
+#CHECK:    Name:
+#CHECK:    Type: SHT_NULL
+#CHECK:    Flags [
+#CHECK:    ]
+#CHECK:    Address: 0x0
+#CHECK:    Offset: 0x0
+#CHECK:    Size: 0
+#CHECK:    Link: 0
+#CHECK:    Info: 0
+#CHECK:    AddressAlignment: 0
+#CHECK:    EntrySize: 0
+#CHECK:  }
+#CHECK:  Section {
+#CHECK:    Index: 1
+#CHECK:    Name: .aaa
+#CHECK:    Type: SHT_PROGBITS
+#CHECK:    Flags [
+#CHECK:      SHF_ALLOC
+#CHECK:    ]
+#CHECK:    Address: 0x2000
+#CHECK:    Offset: 0x1000
+#CHECK:    Size: 8
+#CHECK:    Link: 0
+#CHECK:    Info: 0
+#CHECK:    AddressAlignment: 1
+#CHECK:    EntrySize: 0
+#CHECK:  }
+#CHECK:  Section {
+#CHECK:    Index: 2
+#CHECK:    Name: .bbb
+#CHECK:    Type: SHT_PROGBITS
+#CHECK:    Flags [
+#CHECK:      SHF_ALLOC
+#CHECK:    ]
+#CHECK:    Address: 0x3000
+#CHECK:    Offset: 0x2000
+#CHECK:    Size: 8
+#CHECK:    Link: 0
+#CHECK:    Info: 0
+#CHECK:    AddressAlignment: 1
+#CHECK:    EntrySize: 0
+#CHECK:  }
+#CHECK:  Section {
+#CHECK:    Index: 3
+#CHECK:    Name: .ccc
+#CHECK:    Type: SHT_PROGBITS
+#CHECK:    Flags [
+#CHECK:      SHF_ALLOC
+#CHECK:    ]
+#CHECK:    Address: 0x4008
+#CHECK:    Offset: 0x3008
+#CHECK:    Size: 8
+#CHECK:    Link: 0
+#CHECK:    Info: 0
+#CHECK:    AddressAlignment: 1
+#CHECK:    EntrySize: 0
+#CHECK:  }
+#CHECK:  Section {
+#CHECK:    Index: 4
+#CHECK:    Name: .ddd
+#CHECK:    Type: SHT_PROGBITS
+#CHECK:    Flags [
+#CHECK:      SHF_ALLOC
+#CHECK:    ]
+#CHECK:    Address: 0x5010
+#CHECK:    Offset: 0x4010
+#CHECK:    Size: 8
+#CHECK:    Link: 0
+#CHECK:    Info: 0
+#CHECK:    AddressAlignment: 16
+#CHECK:    EntrySize: 0
+#CHECK:  }
+
+.globl _start
+_start:
+nop
+
+.section .aaa, "a"
+.quad 0
+
+.section .bbb, "a"
+.quad 0
+
+.section .ccc, "a"
+.quad 0
+
+.section .ddd, "a"
+.align 16
+.quad 0
diff --git a/test/ELF/linkerscript/page-size-align.s b/test/ELF/linkerscript/page-size-align.s
new file mode 100644 (file)
index 0000000..771bb13
--- /dev/null
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN:         . = SIZEOF_HEADERS; \
+# RUN:         .text : { *(.text) } \
+# RUN:         . = ALIGN(CONSTANT(MAXPAGESIZE)); \
+# RUN:         . = . + 0x3000; \
+# RUN:         .dynamic : { *(.dynamic) } \
+# RUN:       }" > %t.script
+
+# RUN: ld.lld -T %t.script -z max-page-size=0x4000 %t.o -o %t.so -shared
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+
+# CHECK:      Name: .dynamic
+# CHECK-NEXT: Type: SHT_DYNAMIC
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_ALLOC
+# CHECK-NEXT:   SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x7000
+# CHECK-NEXT: Offset: 0x3000
diff --git a/test/ELF/linkerscript/page-size.s b/test/ELF/linkerscript/page-size.s
new file mode 100644 (file)
index 0000000..330339d
--- /dev/null
@@ -0,0 +1,66 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld -z max-page-size=0x4000 %t -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
+
+# CHECK:      ProgramHeaders [
+# CHECK:        ProgramHeader {
+# CHECK:          Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x200000
+# CHECK-NEXT:     PhysicalAddress: 0x200000
+# CHECK-NEXT:     FileSize: 344
+# CHECK-NEXT:     MemSize: 344
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 16384
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x4000
+# CHECK-NEXT:     VirtualAddress: 0x204000
+# CHECK-NEXT:     PhysicalAddress: 0x204000
+# CHECK-NEXT:     FileSize: 1
+# CHECK-NEXT:     MemSize: 1
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_X
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 16384
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x8000
+# CHECK-NEXT:     VirtualAddress: 0x208000
+# CHECK-NEXT:     PhysicalAddress: 0x208000
+# CHECK-NEXT:     FileSize: 8
+# CHECK-NEXT:     MemSize: 8
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 16384
+# CHECK-NEXT:   }
+
+# RUN: echo "SECTIONS { symbol = CONSTANT(MAXPAGESIZE); }" > %t.script
+# RUN: ld.lld -z max-page-size=0x4000 -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck -check-prefix CHECK-SCRIPT %s
+
+# CHECK-SCRIPT: 0000000000004000 *ABS* 00000000 symbol
+
+# RUN: not ld.lld -z max-page-size=0x1001 -o %t1 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR1 %s
+# ERR1: max-page-size: value isn't a power of 2
+
+# RUN: not ld.lld -z max-page-size=-0x1000 -o %t1 --script %t.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR2 %s
+# ERR2: invalid max-page-size: -0x1000
+
+.global _start
+_start:
+  nop
+
+.section .a, "aw"
+.quad 0
diff --git a/test/ELF/linkerscript/phdr-check.s b/test/ELF/linkerscript/phdr-check.s
new file mode 100644 (file)
index 0000000..c7229ed
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { . = 0x10000000; .text : {*(.text.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_PHDR (0x6)
+# CHECK-NEXT:    Offset: 0x40
+# CHECK-NEXT:    VirtualAddress: 0xFFFF040
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/phdrs-flags.s b/test/ELF/linkerscript/phdrs-flags.s
new file mode 100644 (file)
index 0000000..3cb6432
--- /dev/null
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS FLAGS (1 | 1 + 0x1);} \
+# RUN:       SECTIONS { \
+# RUN:           . = 0x10000200; \
+# RUN:           .text : {*(.text*)} :all \
+# RUN:           .foo : {*(.foo.*)} :all \
+# RUN:           .data : {*(.data.*)} :all}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS FLAGS (0x1);} \
+# RUN:       SECTIONS { \
+# RUN:           . = 0x10000200; \
+# RUN:           .text : {*(.text*)} :all \
+# RUN:           .foo : {*(.foo.*)}  \
+# RUN:           .data : {*(.data.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s
+
+# CHECK:     ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x10000000
+# CHECK-NEXT:    PhysicalAddress: 0x10000000
+# CHECK-NEXT:    FileSize: 521
+# CHECK-NEXT:    MemSize: 521
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_W (0x2)
+# CHECK-NEXT:      PF_X (0x1)
+# CHECK-NEXT:    ]
+
+# DEFHDR:     ProgramHeaders [
+# DEFHDR-NEXT:  ProgramHeader {
+# DEFHDR-NEXT:    Type: PT_LOAD (0x1)
+# DEFHDR-NEXT:    Offset: 0x0
+# DEFHDR-NEXT:    VirtualAddress: 0x10000000
+# DEFHDR-NEXT:    PhysicalAddress: 0x10000000
+# DEFHDR-NEXT:    FileSize: 521
+# DEFHDR-NEXT:    MemSize: 521
+# DEFHDR-NEXT:    Flags [ (0x1)
+# DEFHDR-NEXT:      PF_X (0x1)
+# DEFHDR-NEXT:    ]
+# DEFHDR-NEXT:    Alignment: 4096
+# DEFHDR-NEXT:  }
+
+.global _start
+_start:
+ nop
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .foo.2,"aw"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/phdrs.s b/test/ELF/linkerscript/phdrs.s
new file mode 100644 (file)
index 0000000..025ced9
--- /dev/null
@@ -0,0 +1,143 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \
+# RUN:       SECTIONS { \
+# RUN:           . = 0x10000200; \
+# RUN:           .text : {*(.text*)} :all \
+# RUN:           .foo : {*(.foo.*)} :all \
+# RUN:           .data : {*(.data.*)} :all}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+
+## Check that program headers are not written, unless we explicitly tell
+## lld to do this.
+# RUN: echo "PHDRS {all PT_LOAD;} \
+# RUN:       SECTIONS { \
+# RUN:           . = 0x10000200; \
+# RUN:           /DISCARD/ : {*(.text*)}  \
+# RUN:           .foo : {*(.foo.*)} :all \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=NOPHDR %s
+
+## Check the AT(expr)
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS AT(0x500 + 0x500) ;} \
+# RUN:       SECTIONS { \
+# RUN:           . = 0x10000200; \
+# RUN:           .text : {*(.text*)} :all \
+# RUN:           .foo : {*(.foo.*)} :all \
+# RUN:           .data : {*(.data.*)} :all}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=AT %s
+
+# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \
+# RUN:       SECTIONS { \
+# RUN:           . = 0x10000200; \
+# RUN:           .text : {*(.text*)} :all \
+# RUN:           .foo : {*(.foo.*)}  \
+# RUN:           .data : {*(.data.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s
+
+## Check that error is reported when trying to use phdr which is not listed 
+## inside PHDRS {} block
+## TODO: If script doesn't contain PHDRS {} block then default phdr is always 
+## created and error is not reported.
+# RUN: echo "PHDRS { all PT_LOAD; } \
+# RUN:       SECTIONS { .baz : {*(.foo.*)} :bar }" > %t.script
+# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 | FileCheck --check-prefix=BADHDR %s
+
+# CHECK:     ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD (0x1)
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x10000000
+# CHECK-NEXT:    PhysicalAddress: 0x10000000
+# CHECK-NEXT:    FileSize: 521
+# CHECK-NEXT:    MemSize: 521
+# CHECK-NEXT:    Flags [ (0x7)
+# CHECK-NEXT:      PF_R (0x4)
+# CHECK-NEXT:      PF_W (0x2)
+# CHECK-NEXT:      PF_X (0x1)
+# CHECK-NEXT:    ]
+
+# NOPHDR:     ProgramHeaders [
+# NOPHDR-NEXT:  ProgramHeader {
+# NOPHDR-NEXT:    Type: PT_LOAD (0x1)
+# NOPHDR-NEXT:    Offset: 0x200
+# NOPHDR-NEXT:    VirtualAddress: 0x10000200
+# NOPHDR-NEXT:    PhysicalAddress: 0x10000200
+# NOPHDR-NEXT:    FileSize: 8
+# NOPHDR-NEXT:    MemSize: 8
+# NOPHDR-NEXT:    Flags [ (0x6)
+# NOPHDR-NEXT:      PF_R (0x4)
+# NOPHDR-NEXT:      PF_W (0x2)
+# NOPHDR-NEXT:    ]
+# NOPHDR-NEXT:    Alignment: 4096
+# NOPHDR-NEXT:  }
+# NOPHDR-NEXT: ]
+
+# AT:       ProgramHeaders [
+# AT-NEXT:    ProgramHeader {
+# AT-NEXT:      Type: PT_LOAD (0x1)
+# AT-NEXT:      Offset: 0x0
+# AT-NEXT:      VirtualAddress: 0x10000000
+# AT-NEXT:      PhysicalAddress: 0xA00
+# AT-NEXT:      FileSize: 521
+# AT-NEXT:      MemSize: 521
+# AT-NEXT:      Flags [ (0x7)
+# AT-NEXT:        PF_R (0x4)
+# AT-NEXT:        PF_W (0x2)
+# AT-NEXT:        PF_X (0x1)
+# AT-NEXT:      ]
+
+## Check the numetic values for PHDRS.
+# RUN: echo "PHDRS {text PT_LOAD FILEHDR PHDRS; foo 0x11223344; } \
+# RUN:       SECTIONS { . = SIZEOF_HEADERS; .foo : { *(.foo* .text*) } : text : foo}" > %t1.script
+# RUN: ld.lld -o %t2 --script %t1.script %t
+# RUN: llvm-readobj -program-headers %t2 | FileCheck --check-prefix=INT-PHDRS %s
+
+# INT-PHDRS:      ProgramHeaders [
+# INT-PHDRS:        ProgramHeader {
+# INT-PHDRS:           Type:  (0x11223344)
+# INT-PHDRS-NEXT:      Offset: 0xB0
+# INT-PHDRS-NEXT:      VirtualAddress: 0xB0
+# INT-PHDRS-NEXT:      PhysicalAddress: 0xB0
+# INT-PHDRS-NEXT:      FileSize:
+# INT-PHDRS-NEXT:      MemSize:
+# INT-PHDRS-NEXT:      Flags [
+# INT-PHDRS-NEXT:        PF_R
+# INT-PHDRS-NEXT:        PF_W
+# INT-PHDRS-NEXT:        PF_X
+# INT-PHDRS-NEXT:      ]
+# INT-PHDRS-NEXT:      Alignment:
+# INT-PHDRS-NEXT:    }
+# INT-PHDRS-NEXT:  ]
+
+# DEFHDR:     ProgramHeaders [
+# DEFHDR-NEXT:  ProgramHeader {
+# DEFHDR-NEXT:    Type: PT_LOAD (0x1)
+# DEFHDR-NEXT:    Offset: 0x0
+# DEFHDR-NEXT:    VirtualAddress: 0x10000000
+# DEFHDR-NEXT:    PhysicalAddress: 0x10000000
+# DEFHDR-NEXT:    FileSize: 521
+# DEFHDR-NEXT:    MemSize: 521
+# DEFHDR-NEXT:    Flags [ (0x7)
+# DEFHDR-NEXT:      PF_R (0x4)
+# DEFHDR-NEXT:      PF_W (0x2)
+# DEFHDR-NEXT:      PF_X (0x1)
+# DEFHDR-NEXT:    ]
+
+# BADHDR:       {{.*}}.script:1: section header 'bar' is not listed in PHDRS
+
+.global _start
+_start:
+ nop
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .foo.2,"aw"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/pt_gnu_eh_frame.s b/test/ELF/linkerscript/pt_gnu_eh_frame.s
new file mode 100644 (file)
index 0000000..81b4c63
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.eh_frame*) *(.eh_frame_hdr*) } }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+
+.global _start
+_start:
+ nop
+
+.section .dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
diff --git a/test/ELF/linkerscript/repsection-symbol.s b/test/ELF/linkerscript/repsection-symbol.s
new file mode 100644 (file)
index 0000000..d2d8c9d
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:   . = SIZEOF_HEADERS; \
+# RUN:   .text : { *(.text) } \
+# RUN:   .foo : {foo1 = .;  *(.foo.*) foo2 = .;  *(.bar) foo3 = .;} \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK:      Name: foo1
+# CHECK-NEXT: Value: 0x228
+
+# CHECK:      Name: foo2
+# CHECK-NEXT: Value: 0x230
+
+# CHECK:      Name: foo3
+# CHECK-NEXT: Value: 0x234
+
+.section .foo.1,"a"
+ .long 1
+
+.section .foo.2,"aw"
+ .long 2
+
+ .section .bar,"aw"
+ .long 3
diff --git a/test/ELF/linkerscript/repsection-va.s b/test/ELF/linkerscript/repsection-va.s
new file mode 100644 (file)
index 0000000..8a50fc0
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.foo : {*(.foo.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NOT: .foo
+# CHECK:  .foo          00000008 {{.*}} DATA
+# CHECK-NOT: .foo
+
+
+.global _start
+_start:
+ nop
+
+.section .foo.1,"a"
+foo1:
+ .long 0
+
+.section .foo.2,"aw"
+foo2:
+ .long 0
diff --git a/test/ELF/linkerscript/rosegment.s b/test/ELF/linkerscript/rosegment.s
new file mode 100644 (file)
index 0000000..3201b8b
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Test that with linker scripts we don't create a RO PT_LOAD.
+
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -l %t1 | FileCheck %s
+
+# CHECK-NOT:  Type: PT_LOAD
+
+# CHECK:      Type: PT_LOAD
+# CHECK:      Flags [
+# CHECK-NEXT:   PF_R
+# CHECK-NEXT:   PF_X
+# CHECK-NEXT: ]
+
+# CHECK:      Type: PT_LOAD
+# CHECK:      Flags [
+# CHECK-NEXT:   PF_R
+# CHECK-NEXT:   PF_W
+# CHECK-NEXT: ]
+
+# CHECK-NOT:  Type: PT_LOAD
diff --git a/test/ELF/linkerscript/searchdir.s b/test/ELF/linkerscript/searchdir.s
new file mode 100644 (file)
index 0000000..9fc1a6a
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd \
+# RUN:   %p/Inputs/libsearch-dyn.s -o %tdyn.o
+# RUN: mkdir -p %t.dir
+# RUN: ld.lld -shared %tdyn.o -o %t.dir/libls.so
+# RUN: echo "SEARCH_DIR(\"%t.dir\")" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script -lls %t
+
+.globl _start,_bar
+_start:
diff --git a/test/ELF/linkerscript/section-align.s b/test/ELF/linkerscript/section-align.s
new file mode 100644 (file)
index 0000000..f4bdb0f
--- /dev/null
@@ -0,0 +1,62 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:   .aaa : ALIGN(4096) { *(.aaa) } \
+# RUN:   .bbb : ALIGN(4096 * 4) { *(.bbb) } \
+# RUN:   .ccc : ALIGN(4096 * 8) { *(.ccc) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-readobj -sections %t1 | FileCheck %s
+
+.global _start
+_start:
+ nop
+
+// CHECK:      Name: .aaa
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4096
+// CHECK-NEXT: EntrySize:
+
+.section .aaa, "a"
+.quad 0
+
+// CHECK:      Name: .bbb
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16384
+// CHECK-NEXT: EntrySize:
+
+.section .bbb, "a"
+.quad 0
+
+// CHECK:      Name: .ccc
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 32768
+// CHECK-NEXT: EntrySize:
+
+.section .ccc, "a"
+.quad 0
diff --git a/test/ELF/linkerscript/section-metadata.s b/test/ELF/linkerscript/section-metadata.s
new file mode 100644 (file)
index 0000000..f447240
--- /dev/null
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { .text : { *(.text.bar) *(.text.foo)  } }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# RUN: echo "SECTIONS { .text : { *(.text.foo) *(.text.bar) } }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-objdump -s %t | FileCheck --check-prefix=INV %s
+
+
+# CHECK:      Contents of section .text:
+# CHECK-NEXT: 02000000 00000000 01000000 00000000
+# CHECK:      Contents of section .rodata:
+# CHECK-NEXT: 02000000 00000000 01000000 00000000
+
+# INV:      Contents of section .text:
+# INV-NEXT: 01000000 00000000 02000000 00000000
+# INV:      Contents of section .rodata:
+# INV-NEXT: 01000000 00000000 02000000 00000000
+
+.global _start
+_start:
+
+.section .text.bar,"a",@progbits
+.quad 2
+.section .text.foo,"a",@progbits
+.quad 1
+.section .rodata.foo,"ao",@progbits,.text.foo
+.quad 1
+.section .rodata.bar,"ao",@progbits,.text.bar
+.quad 2
diff --git a/test/ELF/linkerscript/sections-constraint.s b/test/ELF/linkerscript/sections-constraint.s
new file mode 100644 (file)
index 0000000..4d95ec1
--- /dev/null
@@ -0,0 +1,46 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  .writable : ONLY_IF_RW { *(.writable) } \
+# RUN:  .readable : ONLY_IF_RO { *(.readable) }}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=BASE %s
+# BASE: Sections:
+# BASE-NEXT: Idx Name          Size
+# BASE-NEXT:   0               00000000
+# BASE:   .writable     00000004
+# BASE:   .readable     00000004
+
+# RUN: echo "SECTIONS { \
+# RUN:  .foo : ONLY_IF_RO { *(.foo.*) } \
+# RUN:  .writable : ONLY_IF_RW { *(.writable) } \
+# RUN:  .readable : ONLY_IF_RO { *(.readable) }}" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t
+# RUN: llvm-objdump -section-headers %t2 | \
+# RUN:   FileCheck -check-prefix=NO1 %s
+# NO1: Sections:
+# NO1-NEXT: Idx Name          Size
+# NO1-NEXT: 0               00000000
+# NO1:  .writable     00000004
+# NO1:  .foo.2        00000004
+# NO1:  .readable     00000004
+# NO1:  .foo.1        00000004
+
+.global _start
+_start:
+  nop
+
+.section .writable, "aw"
+writable:
+ .long 1
+
+.section .readable, "a"
+readable:
+ .long 2
+
+.section .foo.1, "awx"
+ .long 0
+
+.section .foo.2, "aw"
+ .long 0
diff --git a/test/ELF/linkerscript/sections-constraint2.s b/test/ELF/linkerscript/sections-constraint2.s
new file mode 100644 (file)
index 0000000..e726365
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { zed : ONLY_IF_RO { *(foo) *(bar) } }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t.so -shared
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+
+# CHECK: Sections [
+# CHECK-NOT: zed
+
+.section foo,"aw"
+.quad 1
+
+.section bar, "a"
+.quad 2
diff --git a/test/ELF/linkerscript/sections-constraint3.s b/test/ELF/linkerscript/sections-constraint3.s
new file mode 100644 (file)
index 0000000..259f11e
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { zed : ONLY_IF_RO { abc = 1; *(foo) } }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t.so -shared
+# RUN: llvm-readobj -t %t.so | FileCheck %s
+
+# CHECK: Symbols [
+# CHECK-NOT: abc
+
+.section foo,"aw"
+.quad 1
diff --git a/test/ELF/linkerscript/sections-constraint4.s b/test/ELF/linkerscript/sections-constraint4.s
new file mode 100644 (file)
index 0000000..6c2d4c8
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  .foo : ONLY_IF_RO { *(.foo) } \
+# RUN:  .bar : {bar1 = .; *(.bar) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK: Name: bar1
+
+.global _start
+_start:
+  nop
+
+.section .bar, "aw"
+bar:
+ .long 1
+
+.section .foo, "aw"
+ .long 0
diff --git a/test/ELF/linkerscript/sections-constraint5.s b/test/ELF/linkerscript/sections-constraint5.s
new file mode 100644 (file)
index 0000000..ea14aad
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:         bar : ONLY_IF_RO { sym1 = .; *(foo*) } \
+# RUN:         bar : ONLY_IF_RW { sym2 = .; *(foo*) } \
+# RUN:       }" > %t.script
+
+# RUN: ld.lld -o %t -T %t.script %t.o
+# RUN: llvm-readobj -s -t %t | FileCheck %s
+
+# CHECK: Sections [
+# CHECK:      Name: bar
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_ALLOC
+# CHECK-NEXT:   SHF_WRITE
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 2
+
+# CHECK: Symbols [
+# CHECK-NOT: sym1
+# CHECK:     sym2
+# CHECK-NOT: sym1
+
+.section foo1,"a"
+.byte 0
+
+.section foo2,"aw"
+.byte 0
+
diff --git a/test/ELF/linkerscript/sections-gc.s b/test/ELF/linkerscript/sections-gc.s
new file mode 100644 (file)
index 0000000..d71dc65
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { .text : { *(.text*) } }" > %t.script
+# RUN: ld.lld %t --gc-sections --script %t.script -o %t1
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT:  Name      Size
+# CHECK:       .text     00000001
+
+.section .text.foo, "ax"
+.global _start
+_start:
+  nop
+
+.section .text.bar, "ax"
+.global bar
+bar:
+  nop
diff --git a/test/ELF/linkerscript/sections-gc2.s b/test/ELF/linkerscript/sections-gc2.s
new file mode 100644 (file)
index 0000000..e2941aa
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:         used_in_reloc : { *(used_in_reloc) } \
+# RUN:         used_in_script : { *(used_in_script) } \
+# RUN:         .text : { *(.text) } \
+# RUN:       }" > %t.script
+# RUN: ld.lld -T %t.script -o %t.so %t.o --gc-sections
+# RUN: llvm-objdump -h %t.so | FileCheck %s
+
+# CHECK: Idx Name          Size      Address          Type
+# CHECK-NEXT:  0
+# CHECK-NEXT:    used_in_reloc
+# CHECK-NEXT:    .text
+# CHECK-NEXT:    .comment
+# CHECK-NEXT:    .symtab
+# CHECK-NEXT:    .shstrtab
+# CHECK-NEXT:    .strtab
+
+        .global _start
+_start:
+        .quad __start_used_in_reloc
+
+        .section unused,"a"
+        .quad 0
+
+        .section used_in_script,"a"
+        .quad __start_used_in_script
+
+        .section used_in_reloc,"a"
+        .quad 0
diff --git a/test/ELF/linkerscript/sections-keep.s b/test/ELF/linkerscript/sections-keep.s
new file mode 100644 (file)
index 0000000..feb0bac
--- /dev/null
@@ -0,0 +1,95 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/keep.s -o %t2.o
+
+## First check that section "keep" is garbage collected without using KEEP
+# RUN: echo "SECTIONS { \
+# RUN:  .text : { *(.text) } \
+# RUN:  .keep : { *(.keep) } \
+# RUN:  .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=SECGC %s
+# SECGC:      Sections:
+# SECGC-NEXT: Idx Name          Size
+# SECGC-NEXT:   0               00000000
+# SECGC-NEXT:   1 .text         00000007
+# SECGC-NEXT:   2 .temp         00000004
+
+## Now apply KEEP command to preserve the section.
+# RUN: echo "SECTIONS { \
+# RUN:  .text : { *(.text) } \
+# RUN:  .keep : { KEEP(*(.keep)) } \
+# RUN:  .temp : { *(.temp) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=SECNOGC %s
+# SECNOGC:      Sections:
+# SECNOGC-NEXT: Idx Name          Size
+# SECNOGC-NEXT:   0               00000000
+# SECNOGC-NEXT:   1 .text         00000007
+# SECNOGC-NEXT:   2 .keep         00000004
+# SECNOGC-NEXT:   3 .temp         00000004
+
+## A section name matches two entries in the SECTIONS directive. The
+## first one doesn't have KEEP, the second one does. If section that have
+## KEEP is the first in order then section is NOT collected.
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN:  .keep : { KEEP(*(.keep)) } \
+# RUN:  .nokeep : { *(.keep) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED1 %s
+# MIXED1:      Sections:
+# MIXED1-NEXT: Idx Name          Size
+# MIXED1-NEXT:   0               00000000
+# MIXED1-NEXT:   1 .keep         00000004
+# MIXED1-NEXT:   2 .text         00000007 00000000000000ec TEXT DATA
+# MIXED1-NEXT:   3 .temp         00000004 00000000000000f3 DATA
+# MIXED1-NEXT:   4 .comment      00000008 0000000000000000
+# MIXED1-NEXT:   5 .symtab       00000060 0000000000000000
+# MIXED1-NEXT:   6 .shstrtab     00000036 0000000000000000
+# MIXED1-NEXT:   7 .strtab       00000012 0000000000000000
+
+## The same, but now section without KEEP is at first place.
+## gold and bfd linkers disagree here. gold collects .keep while
+## bfd keeps it. Our current behavior is compatible with bfd although
+## we can choose either way.
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN:  .nokeep : { *(.keep) } \
+# RUN:  .keep : { KEEP(*(.keep)) }}" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED2 %s
+# MIXED2:      Sections:
+# MIXED2-NEXT: Idx Name          Size
+# MIXED2-NEXT:   0               00000000
+# MIXED2-NEXT:   1 .nokeep       00000004 00000000000000e8 DATA
+# MIXED2-NEXT:   2 .text         00000007 00000000000000ec TEXT DATA
+# MIXED2-NEXT:   3 .temp         00000004 00000000000000f3 DATA
+# MIXED2-NEXT:   4 .comment      00000008 0000000000000000
+# MIXED2-NEXT:   5 .symtab       00000060 0000000000000000
+# MIXED2-NEXT:   6 .shstrtab     00000038 0000000000000000
+# MIXED2-NEXT:   7 .strtab       00000012 0000000000000000
+
+# Check file pattern for kept sections.
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN:  .keep : { KEEP(*2.o(.keep)) } \
+# RUN:  }" > %t.script
+# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t2.o %t
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=FILEMATCH %s
+# FILEMATCH:        Contents of section .keep:
+# FILEMATCH-NEXT:   00e8 41414141  AAAA
+
+.global _start
+_start:
+ mov temp, %eax
+
+.section .keep, "a"
+keep:
+ .long 1
+
+.section .temp, "a"
+temp:
+ .long 2
diff --git a/test/ELF/linkerscript/sections-padding.s b/test/ELF/linkerscript/sections-padding.s
new file mode 100644 (file)
index 0000000..91ced2e
--- /dev/null
@@ -0,0 +1,54 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check that padding value works:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x1122 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s
+# YES: 66000011 22000011 22000011 22000011
+
+## Confirming that address was correct:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99887766 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES2 %s
+# YES2: 66998877 66998877 66998877 66998877
+
+## Default padding value is 0x00:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=NO %s
+# NO: 66000000 00000000 00000000 00000000
+
+## Decimal value.
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =777 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=DEC %s
+# DEC: 66000003 09000003 09000003 09000003
+
+## Invalid hex value:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script
+# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \
+# RUN:   | FileCheck --check-prefix=ERR2 %s
+# ERR2: invalid filler expression: 0x99XX
+
+## Check case with space between '=' and expression:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } = 0x1122 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s
+
+## Check case with optional comma following output section command:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x1122, .a : { *(.a*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s
+
+.section        .mysec.1,"a"
+.align  16
+.byte   0x66
+
+.section        .mysec.2,"a"
+.align  16
+.byte   0x66
+
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/sections-sort.s b/test/ELF/linkerscript/sections-sort.s
new file mode 100644 (file)
index 0000000..0e99851
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { .text : {*(.text)} foo : {*(foo)}}" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-objdump --section-headers %t | FileCheck  %s
+
+# Test the section order. This is a case where at least with libstdc++'s
+# stable_sort we used to get a different result.
+
+nop
+
+.section foo, "a"
+.byte 0
+
+# CHECK: Id
+# CHECK-NEXT: 0
+# CHECK-NEXT: 1 .text
+# CHECK-NEXT: 2 foo
+# CHECK-NEXT: 3 .dynsym
+# CHECK-NEXT: 4 .hash
+# CHECK-NEXT: 5 .dynstr
+# CHECK-NEXT: 6 .dynamic
+# CHECK-NEXT: 7 .comment
+# CHECK-NEXT: 8 .symtab
+# CHECK-NEXT: 9 .shstrtab
+# CHECK-NEXT: 10 .strtab
diff --git a/test/ELF/linkerscript/sections.s b/test/ELF/linkerscript/sections.s
new file mode 100644 (file)
index 0000000..dd4b12f
--- /dev/null
@@ -0,0 +1,108 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Empty SECTIONS command.
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+# SECTIONS command with the same order as default.
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          .data : { *(.data) } }" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t2 | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+#             Idx Name          Size
+# SEC-DEFAULT: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-DEFAULT: 2 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-DEFAULT: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-DEFAULT: 5 .comment      00000008 {{[0-9a-f]*}}
+# SEC-DEFAULT: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-DEFAULT: 7 .shstrtab     0000003b {{[0-9a-f]*}}
+# SEC-DEFAULT: 8 .strtab       00000008 {{[0-9a-f]*}}
+
+# Sections are put in order specified in linker script, other than alloc
+# sections going first.
+# RUN: echo "SECTIONS { \
+# RUN:          .bss : { *(.bss) } \
+# RUN:          other : { *(other) } \
+# RUN:          .shstrtab : { *(.shstrtab) } \
+# RUN:          .symtab : { *(.symtab) } \
+# RUN:          .strtab : { *(.strtab) } \
+# RUN:          .data : { *(.data) } \
+# RUN:          .text : { *(.text) } }" > %t.script
+# RUN: ld.lld -o %t3 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t3 | \
+# RUN:   FileCheck -check-prefix=SEC-ORDER %s
+
+#           Idx Name          Size
+# SEC-ORDER: 1 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-ORDER: 2 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 3 .shstrtab     0000003b {{[0-9a-f]*}}
+# SEC-ORDER: 4 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-ORDER: 5 .strtab       00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 6 .comment      00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 7 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 8 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+
+# .text and .data have swapped names but proper sizes and types.
+# RUN: echo "SECTIONS { \
+# RUN:          .data : { *(.text) } \
+# RUN:          .text : { *(.data) } }" > %t.script
+# RUN: ld.lld -o %t4 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t4 | \
+# RUN:   FileCheck -check-prefix=SEC-SWAP-NAMES %s
+
+#                Idx Name          Size
+# SEC-SWAP-NAMES: 1 .data         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-SWAP-NAMES: 2 .text         00000020 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 3 other         00000003 {{[0-9a-f]*}} DATA
+# SEC-SWAP-NAMES: 4 .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-SWAP-NAMES: 5 .comment      00000008 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 7 .shstrtab     0000003b {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 8 .strtab       00000008 {{[0-9a-f]*}}
+
+# Multiple SECTIONS command specifying additional input section descriptions
+# for the same output section description - input sections are merged into
+# one output section.
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          .data : { *(.data) } } \
+# RUN:       SECTIONS { \
+# RUN:          .data : { *(other) } }" > %t.script
+# RUN: ld.lld -o %t6 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t6 | \
+# RUN:   FileCheck -check-prefix=SEC-MULTI %s
+
+#           Idx Name          Size
+# SEC-MULTI:      1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-MULTI-NEXT:   .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-MULTI-NEXT:   .data         00000003 {{[0-9a-f]*}} DATA
+# SEC-MULTI-NEXT:   .bss          00000002 {{[0-9a-f]*}} BSS
+# SEC-MULTI-NEXT:   .comment      00000008 {{[0-9a-f]*}}
+# SEC-MULTI-NEXT:   .symtab       00000030 {{[0-9a-f]*}}
+# SEC-MULTI-NEXT:   .shstrtab     00000035 {{[0-9a-f]*}}
+# SEC-MULTI-NEXT:   .strtab       00000008 {{[0-9a-f]*}}
+
+# Input section pattern contains additional semicolon.
+# Case found in linux kernel script. Check we are able to parse it.
+# RUN: echo "SECTIONS { .text : { ;;*(.text);;S = 0;; } }" > %t.script
+# RUN: ld.lld -o /dev/null --script %t.script %t
+
+.globl _start
+_start:
+    mov $60, %rax
+    mov $42, %rdi
+
+.section .data,"aw"
+.quad 10, 10, 20, 20
+.section other,"aw"
+.short 10
+.byte 20
+.section .bss,"",@nobits
+.short 0
diff --git a/test/ELF/linkerscript/segment-none.s b/test/ELF/linkerscript/segment-none.s
new file mode 100644 (file)
index 0000000..d54e835
--- /dev/null
@@ -0,0 +1,39 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+## Test that section .foo is not placed in any segment when assigned to segment
+## NONE in the linker script and segment NONE is not defined.
+# RUN: echo "PHDRS {text PT_LOAD;} \
+# RUN:       SECTIONS { \
+# RUN:           .text : {*(.text .text*)} :text \
+# RUN:           .foo : {*(.foo)} :NONE \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s
+
+## Test that section .foo is placed in segment NONE when assigned to segment
+## NONE in the linker script and segment NONE is defined.
+# RUN: echo "PHDRS {text PT_LOAD; NONE PT_LOAD;} \
+# RUN:       SECTIONS { \
+# RUN:           .text : {*(.text .text*)} :text \
+# RUN:           .foo : {*(.foo)} :NONE \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o
+# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck --check-prefix=DEFINED %s
+
+# CHECK: Section to Segment mapping:
+# CHECK-NEXT: Segment Sections...
+# CHECK-NOT: .foo
+
+# DEFINED: Section to Segment mapping:
+# DEFINED-NEXT: Segment Sections...
+# DEFINED-NEXT:  00     .text
+# DEFINED-NEXT:  01     .foo
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+foo:
+ .long 0
diff --git a/test/ELF/linkerscript/segment-start.s b/test/ELF/linkerscript/segment-start.s
new file mode 100644 (file)
index 0000000..e46c398
--- /dev/null
@@ -0,0 +1,27 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %S/Inputs/segment-start.script -shared -o %t.so
+// RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s
+
+// CHECK:      Name: foobar1
+// CHECK-NEXT: Value: 0x8001
+
+// CHECK:      Name: foobar2
+// CHECK-NEXT: Value: 0x8002
+
+// CHECK:      Name: foobar3
+// CHECK-NEXT: Value: 0x8003
+
+// CHECK:      Name: foobar4
+// CHECK-NEXT: Value: 0x8004
+
+.data
+.quad foobar1
+.quad foobar2
+.quad foobar3
+.quad foobar4
+
+// RUN: echo "SECTIONS { . = SEGMENT_START(\"foobar\", foo); }" > %t.script
+// RUN: not ld.lld %t.o %t.script -shared -o %t2.so 2>&1 \
+// RUN: | FileCheck --check-prefix=ERR %s
+// ERR: {{.*}}.script:1: symbol not found: foo
diff --git a/test/ELF/linkerscript/sizeof.s b/test/ELF/linkerscript/sizeof.s
new file mode 100644 (file)
index 0000000..4618f79
--- /dev/null
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:   .aaa         : { *(.aaa) } \
+# RUN:   .bbb         : { *(.bbb) } \
+# RUN:   .ccc         : { *(.ccc) } \
+# RUN:   _aaa = SIZEOF(.aaa); \
+# RUN:   _bbb = SIZEOF(.bbb); \
+# RUN:   _ccc = SIZEOF(.ccc); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT:  Idx Name          Size
+# CHECK-NEXT:    0               00000000
+# CHECK-NEXT:    1 .aaa          00000008
+# CHECK-NEXT:    2 .bbb          00000010
+# CHECK-NEXT:    3 .ccc          00000018
+# CHECK:      SYMBOL TABLE:
+# CHECK-NEXT:  0000000000000000 *UND* 00000000
+# CHECK-NEXT:                   .text 00000000 _start
+# CHECK-NEXT:  0000000000000008 *ABS* 00000000 _aaa
+# CHECK-NEXT:  0000000000000010 *ABS* 00000000 _bbb
+# CHECK-NEXT:  0000000000000018 *ABS* 00000000 _ccc
+
+## SIZEOF(.nonexistent_section) should return 0.
+# RUN: echo "SECTIONS { \
+# RUN:   .aaa         : { *(.aaa) } \
+# RUN:   .bbb         : { *(.bbb) } \
+# RUN:   .ccc         : { *(.ccc) } \
+# RUN:   _aaa = SIZEOF(.foo); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t -section-headers %t1 | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK2: 0000000000000000 *ABS* 00000000 _aaa
+
+.global _start
+_start:
+ nop
+
+.section .aaa,"a"
+ .quad 0
+
+.section .bbb,"a"
+ .quad 0
+ .quad 0
+
+.section .ccc,"a"
+ .quad 0
+ .quad 0
+ .quad 0
diff --git a/test/ELF/linkerscript/sizeofheaders.s b/test/ELF/linkerscript/sizeofheaders.s
new file mode 100644 (file)
index 0000000..3cc7074
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo " SECTIONS {             \
+# RUN:          . = SIZEOF_HEADERS;  \
+# RUN:          _size = SIZEOF_HEADERS;  \
+# RUN:          .text : {*(.text*)} \
+# RUN:          }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+
+#CHECK:      SYMBOL TABLE:
+#CHECK-NEXT:  0000000000000000 *UND* 00000000
+#CHECK-NEXT:  00000000000000e8 .text 00000000 _start
+#CHECK-NEXT:  00000000000000e8 *ABS* 00000000 _size
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/sort-constructors.s b/test/ELF/linkerscript/sort-constructors.s
new file mode 100644 (file)
index 0000000..a0c23af
--- /dev/null
@@ -0,0 +1,5 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: echo "SECTIONS { .aaa : { SORT(CONSTRUCTORS) } }" > %t1.script
+# RUN: ld.lld -shared -o %t1 --script %t1.script %t1.o
+# RUN: llvm-readobj %t1 > /dev/null
diff --git a/test/ELF/linkerscript/sort-init.s b/test/ELF/linkerscript/sort-init.s
new file mode 100644 (file)
index 0000000..894b8ae
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: echo "SECTIONS { .init_array : { *(SORT_BY_INIT_PRIORITY(.init_array.*)) } }" > %t1.script
+# RUN: ld.lld --script %t1.script %t1.o -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+# CHECK:      Contents of section .init_array:
+# CHECK-NEXT: 03020000 00000000 010405
+
+.globl _start
+_start:
+  nop
+
+.section .init_array, "aw", @init_array
+  .align 8
+  .byte 1
+.section .init_array.100, "aw", @init_array
+  .long 2
+.section .init_array.5, "aw", @init_array
+  .byte 3
+.section .init_array, "aw", @init_array
+  .byte 4
+.section .init_array, "aw", @init_array
+  .byte 5
diff --git a/test/ELF/linkerscript/sort-nested.s b/test/ELF/linkerscript/sort-nested.s
new file mode 100644 (file)
index 0000000..fb1d1a3
--- /dev/null
@@ -0,0 +1,50 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/sort-nested.s -o %t2.o
+
+## Check sorting first by alignment and then by name.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.aaa.*))) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=SORTED_AN %s
+# SORTED_AN:      Contents of section .aaa:
+# SORTED_AN-NEXT:   01000000 00000000 00000000 00000000
+# SORTED_AN-NEXT:   11000000 00000000 00000000 00000000
+# SORTED_AN-NEXT:   55000000 00000000 22000000 00000000
+# SORTED_AN-NEXT:   02000000 00000000
+
+## Check sorting first by name and then by alignment.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(SORT_BY_ALIGNMENT(.aaa.*))) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SORTED_NA %s
+# SORTED_NA: Contents of section .aaa:
+# SORTED_NA:   01000000 00000000 00000000 00000000
+# SORTED_NA:   11000000 00000000 22000000 00000000
+# SORTED_NA:   02000000 00000000 00000000 00000000
+# SORTED_NA:   55000000 00000000
+
+## If the section sorting command in linker script isn't nested, the
+## command line option will make the section sorting command to be treated
+## as nested sorting command.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_ALIGNMENT(.aaa.*)) } }" > %t3.script
+# RUN: ld.lld --sort-section name -o %t3 --script %t3.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_AN %s
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(.aaa.*)) } }" > %t4.script
+# RUN: ld.lld --sort-section alignment -o %t4 --script %t4.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t4 | FileCheck -check-prefix=SORTED_NA %s
+
+.global _start
+_start:
+ nop
+
+.section .aaa.1, "a"
+.align 32
+.quad 1
+
+.section .aaa.2, "a"
+.align 2
+.quad 2
+
+.section .aaa.5, "a"
+.align 16
+.quad 0x55
diff --git a/test/ELF/linkerscript/sort-non-script.s b/test/ELF/linkerscript/sort-non-script.s
new file mode 100644 (file)
index 0000000..b051760
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+
+# RUN: echo "SECTIONS { foo : {*(foo)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
+
+# CHECK:      .text    {{.*}}   AX
+# CHECK-NEXT: .dynsym  {{.*}}   A
+# CHECK-NEXT: .hash    {{.*}}   A
+# CHECK-NEXT: .dynstr  {{.*}}   A
+# CHECK-NEXT: foo      {{.*}}  WA
+# CHECK-NEXT: .dynamic {{.*}}  WA
+
+.section foo, "aw"
+.byte 0
diff --git a/test/ELF/linkerscript/sort.s b/test/ELF/linkerscript/sort.s
new file mode 100644 (file)
index 0000000..6390ced
--- /dev/null
@@ -0,0 +1,120 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %p/Inputs/sort.s -o %t2.o
+
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=UNSORTED %s
+# UNSORTED:       Contents of section .aaa:
+# UNSORTED-NEXT:   55000000 00000000 00000000 00000000
+# UNSORTED-NEXT:   00000000 00000000 00000000 00000000
+# UNSORTED-NEXT:   11000000 00000000 33000000 00000000
+# UNSORTED-NEXT:   22000000 00000000 44000000 00000000
+# UNSORTED-NEXT:   05000000 00000000 01000000 00000000
+# UNSORTED-NEXT:   03000000 00000000 02000000 00000000
+# UNSORTED-NEXT:   04000000 00000000
+
+## Check that SORT works (sorted by name of section).
+# RUN: echo "SECTIONS { .aaa : { *(SORT(.aaa.*)) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SORTED_A %s
+# SORTED_A:      Contents of section .aaa:
+# SORTED_A-NEXT:  11000000 00000000 01000000 00000000
+# SORTED_A-NEXT:  22000000 00000000 02000000 00000000
+# SORTED_A-NEXT:  33000000 00000000 03000000 00000000
+# SORTED_A-NEXT:  44000000 00000000 00000000 00000000
+# SORTED_A-NEXT:  04000000 00000000 55000000 00000000
+# SORTED_A-NEXT:  00000000 00000000 00000000 00000000
+# SORTED_A-NEXT:  05000000 00000000
+
+## When we switch the order of files, check that sorting by
+## section names is stable.
+# RUN: echo "SECTIONS { .aaa : { *(SORT(.aaa.*)) } }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_B %s
+# SORTED_B:      Contents of section .aaa:
+# SORTED_B-NEXT:  01000000 00000000 00000000 00000000
+# SORTED_B-NEXT:  00000000 00000000 00000000 00000000
+# SORTED_B-NEXT:  11000000 00000000 02000000 00000000
+# SORTED_B-NEXT:  22000000 00000000 03000000 00000000
+# SORTED_B-NEXT:  33000000 00000000 00000000 00000000
+# SORTED_B-NEXT:  04000000 00000000 44000000 00000000
+# SORTED_B-NEXT:  05000000 00000000 55000000 00000000
+
+## Check that SORT surrounded with KEEP also works.
+# RUN: echo "SECTIONS { .aaa : { KEEP (*(SORT(.aaa.*))) } }" > %t3.script
+# RUN: ld.lld -o %t3 --script %t3.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t3 | FileCheck -check-prefix=SORTED_A %s
+
+## Check that SORT_BY_NAME works (SORT is alias).
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(.aaa.*)) } }" > %t4.script
+# RUN: ld.lld -o %t4 --script %t4.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t4 | FileCheck -check-prefix=SORTED_A %s
+
+## Check that sections ordered by alignment.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_ALIGNMENT(.aaa.*)) } }" > %t5.script
+# RUN: ld.lld -o %t5 --script %t5.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t5 | FileCheck -check-prefix=SORTED_ALIGNMENT %s
+# SORTED_ALIGNMENT:      Contents of section .aaa:
+# SORTED_ALIGNMENT-NEXT:  05000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT:  00000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT:  11000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT:  04000000 00000000 00000000 00000000
+# SORTED_ALIGNMENT-NEXT:  22000000 00000000 03000000 00000000
+# SORTED_ALIGNMENT-NEXT:  33000000 00000000 02000000 00000000
+# SORTED_ALIGNMENT-NEXT:  44000000 00000000 01000000 00000000
+# SORTED_ALIGNMENT-NEXT:  55000000 00000000
+
+## SORT_NONE itself does not sort anything.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_NONE(.aaa.*)) } }" > %t6.script
+# RUN: ld.lld -o %t7 --script %t6.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t7 | FileCheck -check-prefix=UNSORTED %s
+
+## Check --sort-section alignment option.
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t7.script
+# RUN: ld.lld --sort-section alignment -o %t8 --script %t7.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t8 | FileCheck -check-prefix=SORTED_ALIGNMENT %s
+
+## Check --sort-section= form.
+# RUN: ld.lld --sort-section=alignment -o %t8_1 --script %t7.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t8_1 | FileCheck -check-prefix=SORTED_ALIGNMENT %s
+
+## Check --sort-section name option.
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t8.script
+# RUN: ld.lld --sort-section name -o %t9 --script %t8.script %t1.o %t2.o
+# RUN: llvm-objdump -s %t9 | FileCheck -check-prefix=SORTED_B %s
+
+## SORT_NONE disables the --sort-section.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_NONE(.aaa.*)) } }" > %t9.script
+# RUN: ld.lld --sort-section name -o %t10 --script %t9.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t10 | FileCheck -check-prefix=UNSORTED %s
+
+## SORT_NONE as a inner sort directive.
+# RUN: echo "SECTIONS { .aaa : { *(SORT_BY_NAME(SORT_NONE(.aaa.*))) } }" > %t10.script
+# RUN: ld.lld -o %t11 --script %t10.script %t2.o %t1.o
+# RUN: llvm-objdump -s %t11 | FileCheck -check-prefix=SORTED_A %s
+
+.global _start
+_start:
+ nop
+
+.section .aaa.5, "a"
+.align 32
+.quad 5
+
+.section .aaa.1, "a"
+.align 2
+.quad 1
+
+.section .aaa.3, "a"
+.align 8
+.quad 3
+
+.section .aaa.2, "a"
+.align 4
+.quad 2
+
+.section .aaa.4, "a"
+.align 16
+.quad 4
diff --git a/test/ELF/linkerscript/sort2.s b/test/ELF/linkerscript/sort2.s
new file mode 100644 (file)
index 0000000..1d42093
--- /dev/null
@@ -0,0 +1,39 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile1.o
+
+# RUN: echo "SECTIONS { .abc : { *(SORT(.foo.*) .bar.*) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %tfile1.o
+# RUN: llvm-objdump -s %t1 | FileCheck %s
+
+# CHECK:  Contents of section .abc:
+# CHECK:   01000000 00000000 02000000 00000000
+# CHECK:   03000000 00000000 04000000 00000000
+# CHECK:   06000000 00000000 05000000 00000000
+
+# RUN: echo "SECTIONS { \
+# RUN:   .abc : { *(SORT(.foo.* EXCLUDE_FILE (*file1.o) .bar.*) .bar.*) } \
+# RUN:  }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %tfile1.o
+# RUN: llvm-objdump -s %t2 | FileCheck %s
+
+.text
+.globl _start
+_start:
+
+.section .foo.2,"a"
+ .quad 2
+
+.section .foo.3,"a"
+ .quad 3
+
+.section .foo.1,"a"
+ .quad 1
+
+.section .bar.4,"a"
+ .quad 4
+
+.section .bar.6,"a"
+ .quad 6
+
+.section .bar.5,"a"
+ .quad 5
diff --git a/test/ELF/linkerscript/start-end.s b/test/ELF/linkerscript/start-end.s
new file mode 100644 (file)
index 0000000..b68606a
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:      .init_array : { \
+# RUN:        __init_array_start = .; \
+# RUN:        *(.init_array) \
+# RUN:        __init_array_end = .; } }" > %t.script
+# RUN: ld.lld %t.o -script %t.script -o %t 2>&1
+
+.globl _start
+.text
+_start:
+  nop
+
+.section .init_array, "aw"
+  .quad 0
diff --git a/test/ELF/linkerscript/subalign.s b/test/ELF/linkerscript/subalign.s
new file mode 100644 (file)
index 0000000..8b441d4
--- /dev/null
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t1.o
+# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=NOALIGN %s
+# NOALIGN:      Contents of section .aaa:
+# NOALIGN-NEXT:   01000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   00000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   02000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   00000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   03000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   00000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   00000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   00000000 00000000 00000000 00000000
+# NOALIGN-NEXT:   04000000 00000000
+
+# RUN: echo "SECTIONS { .aaa : SUBALIGN(1) { *(.aaa.*) } }" > %t2.script
+# RUN: ld.lld -o %t2 --script %t2.script %t1.o
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SUBALIGN %s
+# SUBALIGN: Contents of section .aaa:
+# SUBALIGN:   01000000 00000000 02000000 00000000
+# SUBALIGN:   03000000 00000000 04000000 00000000
+
+.global _start
+_start:
+ nop
+
+.section .aaa.1, "a"
+.align 16
+.quad 1
+
+.section .aaa.2, "a"
+.align 32
+.quad 2
+
+.section .aaa.3, "a"
+.align 64
+.quad 3
+
+.section .aaa.4, "a"
+.align 128
+.quad 4
diff --git a/test/ELF/linkerscript/symbol-assignexpr.s b/test/ELF/linkerscript/symbol-assignexpr.s
new file mode 100644 (file)
index 0000000..14a1f08
--- /dev/null
@@ -0,0 +1,59 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:         symbol = CONSTANT(MAXPAGESIZE); \
+# RUN:         symbol2 = symbol + 0x1234; \
+# RUN:         symbol3 = symbol2; \
+# RUN:         symbol4 = symbol + -4; \
+# RUN:         symbol5 = symbol - ~ 0xfffb; \
+# RUN:         symbol6 = symbol - ~(0xfff0 + 0xb); \
+# RUN:         symbol7 = symbol - ~ 0xfffb + 4; \
+# RUN:         symbol8 = ~ 0xffff + 4; \
+# RUN:         symbol9 = - 4; \
+# RUN:         symbol10 = 0xfedcba9876543210; \
+# RUN:         symbol11 = ((0x28000 + 0x1fff) & ~(0x1000 + -1)); \
+# RUN:         symbol12 = 0x1234; \
+# RUN:         symbol12 += 1; \
+# RUN:         bar = 0x5678; \
+# RUN:         baz = 0x9abc; \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+
+# CHECK:      SYMBOL TABLE:
+# CHECK-NEXT: 0000000000000000 *UND* 00000000
+# CHECK-NEXT: 0000000000000000 .text 00000000 _start
+# CHECK-NEXT: 0000000000005678 *ABS* 00000000 bar
+# CHECK-NEXT: 0000000000009abc *ABS* 00000000 baz
+# CHECK-NEXT: 0000000000000001 .text 00000000 foo
+# CHECK-NEXT: 0000000000001000 *ABS* 00000000 symbol
+# CHECK-NEXT: 0000000000002234 *ABS* 00000000 symbol2
+# CHECK-NEXT: 0000000000002234 *ABS* 00000000 symbol3
+# CHECK-NEXT: 0000000000000ffc *ABS* 00000000 symbol4
+# CHECK-NEXT: 0000000000010ffc *ABS* 00000000 symbol5
+# CHECK-NEXT: 0000000000010ffc *ABS* 00000000 symbol6
+# CHECK-NEXT: 0000000000011000 *ABS* 00000000 symbol7
+# CHECK-NEXT: ffffffffffff0004 *ABS* 00000000 symbol8
+# CHECK-NEXT: fffffffffffffffc *ABS* 00000000 symbol9
+# CHECK-NEXT: fedcba9876543210 *ABS* 00000000 symbol10
+# CHECK-NEXT: 0000000000029000 *ABS* 00000000 symbol11
+# CHECK-NEXT: 0000000000001235 *ABS* 00000000 symbol12
+
+# RUN: echo "SECTIONS { symbol2 = symbol; }" > %t2.script
+# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR %s
+# ERR: {{.*}}.script:1: symbol not found: symbol
+
+.global _start
+_start:
+ nop
+
+.global foo
+foo:
+ nop
+
+.global bar
+bar = 0x1234
+
+.comm baz,8,8
diff --git a/test/ELF/linkerscript/symbol-conflict.s b/test/ELF/linkerscript/symbol-conflict.s
new file mode 100644 (file)
index 0000000..dcca7c1
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : {*(.text.*)} end = .;}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: 00000000000000e9         .text    00000000 end
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/symbol-memoryexpr.s b/test/ELF/linkerscript/symbol-memoryexpr.s
new file mode 100644 (file)
index 0000000..9c75274
--- /dev/null
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "MEMORY { \
+# RUN:   ram (rwx)  : ORIGIN = 0x8000, LENGTH = 256K \
+# RUN: } \
+# RUN: SECTIONS { \
+# RUN:         origin = ORIGIN(ram); \
+# RUN:         length = LENGTH(ram); \
+# RUN:         end    = ORIGIN(ram) + LENGTH(ram); \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+
+# CHECK:      SYMBOL TABLE:
+# CHECK-NEXT: 0000000000000000 *UND* 00000000
+# CHECK-NEXT: 0000000000008000 .text 00000000 _start
+# CHECK-NEXT: 0000000000008000 *ABS* 00000000 origin
+# CHECK-NEXT: 0000000000040000 *ABS* 00000000 length
+# CHECK-NEXT: 0000000000048000 *ABS* 00000000 end
+
+# RUN: echo "SECTIONS { \
+# RUN:         no_exist_origin = ORIGIN(ram); \
+# RUN:         no_exist_length = LENGTH(ram); \
+# RUN:       }" > %t2.script
+# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \
+# RUN:  | FileCheck -check-prefix=ERR %s
+# ERR: {{.*}}.script:1: memory region not defined: ram
+
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/linkerscript/symbol-only.s b/test/ELF/linkerscript/symbol-only.s
new file mode 100644 (file)
index 0000000..2fb5726
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN:  abc : { foo = .; } \
+# RUN:  . = ALIGN(0x1000); \
+# RUN:  bar : { *(bar) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-objdump -section-headers -t %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK:          abc           00000000 [[ADDR:[0-9a-f]*]] DATA
+# CHECK-NEXT:     bar           00000000 0000000000001000 DATA
+
+# CHECK: SYMBOL TABLE:
+# CHECK:     [[ADDR]]         abc                00000000 foo
+
+.section bar, "a"
diff --git a/test/ELF/linkerscript/symbol-reserved.s b/test/ELF/linkerscript/symbol-reserved.s
new file mode 100644 (file)
index 0000000..e0b2595
--- /dev/null
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "PROVIDE_HIDDEN(newsym = __ehdr_start + 5);" > %t.script
+# RUN: ld.lld -o %t1 %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+
+# CHECK: 0000000000200005 .text 00000000 .hidden newsym
+
+# RUN: ld.lld -o %t1.so %t.script %t -shared
+# RUN: llvm-objdump -t %t1.so | FileCheck --check-prefix=SHARED %s
+
+# SHARED: 0000000000000005 .dynsym 00000000 .hidden newsym
+
+# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(__ehdr_start, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script
+# RUN: ld.lld -o %t1 %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=ALIGNED %s
+
+# ALIGNED: 0000000000200005 .text 00000000 .hidden newsym
+
+.global _start
+_start:
+  lea newsym(%rip),%rax
diff --git a/test/ELF/linkerscript/symbolreferenced.s b/test/ELF/linkerscript/symbolreferenced.s
new file mode 100644 (file)
index 0000000..c2925b1
--- /dev/null
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Provide new symbol. The value should be 1, like set in PROVIDE()
+# RUN: echo "SECTIONS { PROVIDE(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE1 %s
+# PROVIDE1: 0000000000000001         *ABS*    00000000 newsym
+
+# Provide new symbol (hidden). The value should be 1
+# RUN: echo "SECTIONS { PROVIDE_HIDDEN(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN1 %s
+# HIDDEN1: 0000000000000001         *ABS*    00000000 .hidden newsym
+
+.global _start
+_start:
+ nop
+
+.globl patatino
+patatino:
+  movl newsym, %eax
diff --git a/test/ELF/linkerscript/symbols-non-alloc.s b/test/ELF/linkerscript/symbols-non-alloc.s
new file mode 100644 (file)
index 0000000..e51a39e
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; \
+# RUN:  .text : { *(.text) }                \
+# RUN:  .nonalloc : { *(.nonalloc) }        \
+# RUN:  Sym = .;                            \
+# RUN:  }" > %t.script
+# RUN: ld.lld -o %t2 --script %t.script %t
+# RUN: llvm-objdump -section-headers -t %t2 | FileCheck %s
+
+# CHECK: Sections:
+# CHECK:  .nonalloc     00000008 0000000000000000
+
+# CHECK: SYMBOL TABLE:
+# CHECK:  0000000000000008 .nonalloc 00000000 Sym
+
+.section .nonalloc,""
+ .quad 0
diff --git a/test/ELF/linkerscript/symbols-synthetic.s b/test/ELF/linkerscript/symbols-synthetic.s
new file mode 100644 (file)
index 0000000..95cdae9
--- /dev/null
@@ -0,0 +1,98 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# Simple symbol assignment within input section list. The '.' symbol
+# is not location counter but offset from the beginning of output
+# section .foo
+# RUN: echo "SECTIONS { \
+# RUN:          . = SIZEOF_HEADERS; \
+# RUN:          .foo : { \
+# RUN:              begin_foo = .; \
+# RUN:              PROVIDE(_begin_sec = .); \
+# RUN:              *(.foo) \
+# RUN:              end_foo = .; \
+# RUN:              PROVIDE_HIDDEN(_end_sec = .); \
+# RUN:              PROVIDE(_end_sec_abs = ABSOLUTE(.)); \
+# RUN:              size_foo_1 = SIZEOF(.foo); \
+# RUN:              size_foo_1_abs = ABSOLUTE(SIZEOF(.foo)); \
+# RUN:              . = ALIGN(0x1000); \
+# RUN:              begin_bar = .; \
+# RUN:              *(.bar) \
+# RUN:              end_bar = .; \
+# RUN:              size_foo_2 = SIZEOF(.foo); } \
+# RUN:          size_foo_3 = SIZEOF(.foo); \
+# RUN:          .eh_frame_hdr : { \
+# RUN:             __eh_frame_hdr_start = .; \
+# RUN:             __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10)); \
+# RUN:             *(.eh_frame_hdr) \
+# RUN:             __eh_frame_hdr_end = .; \
+# RUN:             __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10)); } \
+# RUN:          .eh_frame : { } \
+# RUN:       }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
+
+# Check that the following script is processed without errors
+# RUN: echo "SECTIONS { \
+# RUN:          .eh_frame_hdr : { \
+# RUN:             PROVIDE_HIDDEN(_begin_sec = .); \
+# RUN:             *(.eh_frame_hdr) \
+# RUN:             *(.eh_frame_hdr) \
+# RUN:             PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \
+# RUN:             PROVIDE_HIDDEN(_end_sec = .); } \
+# RUN:         }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+
+# Check that we can specify synthetic symbols without defining SECTIONS.
+# RUN: echo "PROVIDE_HIDDEN(_begin_sec = _start); \
+# RUN:       PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text));" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=NO-SEC %s
+
+# Check that we can do the same as above inside SECTIONS block.
+# RUN: echo "SECTIONS { \
+# RUN:        . = 0x201000; \
+# RUN:        .text : { *(.text) } \
+# RUN:        PROVIDE_HIDDEN(_begin_sec = ADDR(.text)); \
+# RUN:        PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text)); }" > %t.script
+# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=IN-SEC %s
+
+# SIMPLE:      0000000000000128         .foo    00000000 .hidden _end_sec
+# SIMPLE-NEXT: 0000000000000120         .foo    00000000 _begin_sec
+# SIMPLE-NEXT: 0000000000000128         *ABS*   00000000 _end_sec_abs
+# SIMPLE-NEXT: 0000000000001048         .text   00000000 _start
+# SIMPLE-NEXT: 0000000000000120         .foo    00000000 begin_foo
+# SIMPLE-NEXT: 0000000000000128         .foo    00000000 end_foo
+# SIMPLE-NEXT: 0000000000000008         *ABS*   00000000 size_foo_1
+# SIMPLE-NEXT: 0000000000000008         *ABS*   00000000 size_foo_1_abs
+# SIMPLE-NEXT: 0000000000001000         .foo    00000000 begin_bar
+# SIMPLE-NEXT: 0000000000001004         .foo    00000000 end_bar
+# SIMPLE-NEXT: 0000000000000ee4         *ABS*   00000000 size_foo_2
+# SIMPLE-NEXT: 0000000000000ee4         *ABS*   00000000 size_foo_3
+# SIMPLE-NEXT: 0000000000001004         .eh_frame_hdr     00000000 __eh_frame_hdr_start
+# SIMPLE-NEXT: 0000000000001010         *ABS*             00000000 __eh_frame_hdr_start2
+# SIMPLE-NEXT: 0000000000001018         .eh_frame_hdr     00000000 __eh_frame_hdr_end
+# SIMPLE-NEXT: 0000000000001020         *ABS*             00000000 __eh_frame_hdr_end2
+
+# NO-SEC:       0000000000201000         .text     00000000 .hidden _begin_sec
+# NO-SEC-NEXT:  0000000000201001         .text     00000000 .hidden _end_sec
+
+# IN-SEC:       0000000000201000         .text     00000000 .hidden _begin_sec
+# IN-SEC-NEXT:  0000000000201001         .text     00000000 .hidden _end_sec
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 0
+
+.section .bar,"a"
+ .long 0
+
+.section .dah,"ax",@progbits
+ .cfi_startproc
+ nop
+ .cfi_endproc
+
+.global _begin_sec, _end_sec, _end_sec_abs
diff --git a/test/ELF/linkerscript/symbols.s b/test/ELF/linkerscript/symbols.s
new file mode 100644 (file)
index 0000000..4656635
--- /dev/null
@@ -0,0 +1,84 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Simple symbol assignment. Should raise conflict in case we
+# have duplicates in any input section, but currently simply
+# replaces the value.
+# RUN: echo "SECTIONS {.text : {*(.text.*)} text_end = .;}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
+# SIMPLE:                               .text    00000000 text_end
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "SECTIONS { PROVIDE(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE1 %s
+# PROVIDE1-NOT: 0000000000000001         *ABS*    00000000 newsym
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "SECTIONS { PROVIDE_HIDDEN(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN1 %s
+# HIDDEN1-NOT: 0000000000000001         *ABS*    00000000 .hidden newsym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE()
+# RUN: echo "SECTIONS { PROVIDE(somesym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE2 %s
+# PROVIDE2: 0000000000000000         *ABS*    00000000 somesym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE_HIDDEN(). Visibility should not change
+# RUN: echo "SECTIONS { PROVIDE_HIDDEN(somesym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN2 %s
+# HIDDEN2: 0000000000000000         *ABS*    00000000 somesym
+
+# Hidden symbol assignment.
+# RUN: echo "SECTIONS { HIDDEN(newsym = 1);}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN3 %s
+# HIDDEN3: 0000000000000001         *ABS*    00000000 .hidden newsym
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "PROVIDE(newsym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE4 %s
+# PROVIDE4-NOT: 0000000000000001         *ABS*    00000000 newsym
+
+# The symbol is not referenced. Don't provide it.
+# RUN: echo "PROVIDE_HIDDEN(newsym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN4 %s
+# HIDDEN4-NOT: 0000000000000001         *ABS*    00000000 .hidden newsym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE()
+# RUN: echo "PROVIDE(somesym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=PROVIDE5 %s
+# PROVIDE5: 0000000000000000         *ABS*    00000000 somesym
+
+# Provide existing symbol. The value should be 0, even though we
+# have value of 1 in PROVIDE_HIDDEN(). Visibility should not change
+# RUN: echo "PROVIDE_HIDDEN(somesym = 1);" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=HIDDEN5 %s
+# HIDDEN5: 0000000000000000         *ABS*    00000000 somesym
+
+# Simple symbol assignment. All three symbols should have the
+# same value.
+# RUN: echo "foo = 0x100; SECTIONS { bar = foo; } baz = bar;" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE2 %s
+# SIMPLE2: 0000000000000100         *ABS*    00000000 foo
+# SIMPLE2: 0000000000000100         *ABS*    00000000 bar
+# SIMPLE2: 0000000000000100         *ABS*    00000000 baz
+
+.global _start
+_start:
+ nop
+
+.global somesym
+somesym = 0
diff --git a/test/ELF/linkerscript/tbss.s b/test/ELF/linkerscript/tbss.s
new file mode 100644 (file)
index 0000000..de8ed50
--- /dev/null
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:   . = SIZEOF_HEADERS; \
+# RUN:   .text : { *(.text) } \
+# RUN:   foo : { *(foo) } \
+# RUN:   bar : { *(bar) } \
+# RUN: }" > %t.script
+# RUN: ld.lld -T %t.script %t.o -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# test that a tbss section doesn't use address space.
+
+# CHECK:        Name: foo
+# CHECK-NEXT:   Type: SHT_NOBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_TLS
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x[[ADDR:.*]]
+# CHECK-NEXT:   Offset: 0x[[ADDR]]
+# CHECK-NEXT:   Size: 4
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: bar
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x[[ADDR]]
+
+        .section foo,"awT",@nobits
+        .long   0
+        .section bar, "aw"
+        .long 0
diff --git a/test/ELF/linkerscript/ttext-script.s b/test/ELF/linkerscript/ttext-script.s
new file mode 100644 (file)
index 0000000..9dcde9b
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text 0x200000 : { *(.text) } }" > %t.script
+# RUN: ld.lld -T %t.script -Ttext 0x100000 %t.o -o %t
+# RUN: llvm-readobj --elf-output-style=GNU -s  %t | FileCheck %s
+
+# CHECK: .text             PROGBITS        0000000000100000
+
+.global _start
+_start:
+nop
diff --git a/test/ELF/linkerscript/undef.s b/test/ELF/linkerscript/undef.s
new file mode 100644 (file)
index 0000000..85ad076
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS { patatino = 0x1234; }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+# CHECK: 0000000000001234         *ABS*    00000000 patatino
+
+.global _start
+_start:
+  call patatino
diff --git a/test/ELF/linkerscript/unused-synthetic.s b/test/ELF/linkerscript/unused-synthetic.s
new file mode 100644 (file)
index 0000000..c9295ff
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:    .got  : { *(.got) } \
+# RUN:    .plt  : { *(.plt) } \
+# RUN:    .text : { *(.text) } \
+# RUN:  }" > %t.script
+# RUN: ld.lld -shared -o %t.so --script %t.script %t.o
+
+# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
+# CHECK-NOT:  .got
+# CHECK-NOT:  .plt
+# CHECK:      .text
+# CHECK-NEXT: .dynsym
+
+.global _start
+_start:
+  nop
diff --git a/test/ELF/linkerscript/va.s b/test/ELF/linkerscript/va.s
new file mode 100644 (file)
index 0000000..854ebce
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {}" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size      Address          Type
+# CHECK-NEXT:   0               00000000 0000000000000000
+# CHECK-NEXT:   1 .text         00000001 0000000000000000 TEXT DATA
+# CHECK-NEXT:   2 .foo          00000004 0000000000000001 DATA
+# CHECK-NEXT:   3 .boo          00000004 0000000000000005 DATA
+
+.global _start
+_start:
+ nop
+
+.section .foo, "a"
+foo:
+ .long 0
+
+.section .boo, "a"
+boo:
+ .long 0
diff --git a/test/ELF/linkerscript/visibility.s b/test/ELF/linkerscript/visibility.s
new file mode 100644 (file)
index 0000000..9d9fcf0
--- /dev/null
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { foo = .; }" > %t1.script
+# RUN: ld.lld -o %t1 --script %t1.script %t.o -shared
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK:      Symbol {
+# CHECK:        Name: foo
+# CHECK-NEXT:   Value:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Local
+# CHECK-NEXT:   Type:
+# CHECK-NEXT:   Other [
+# CHECK-NEXT:     STV_HIDDEN
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section:
+# CHECK-NEXT: }
+
+        .data
+        .hidden foo
+        .long foo
diff --git a/test/ELF/linkerscript/wildcards.s b/test/ELF/linkerscript/wildcards.s
new file mode 100644 (file)
index 0000000..4e9469e
--- /dev/null
@@ -0,0 +1,83 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Default case: abc and abx included in text.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.abc .abx) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+# SEC-DEFAULT:      Sections:
+# SEC-DEFAULT-NEXT: Idx Name          Size
+# SEC-DEFAULT-NEXT:   0               00000000
+# SEC-DEFAULT-NEXT:   1 .text         00000008
+# SEC-DEFAULT-NEXT:   2 .abcd         00000004
+# SEC-DEFAULT-NEXT:   3 .ad           00000004
+# SEC-DEFAULT-NEXT:   4 .ag           00000004
+# SEC-DEFAULT-NEXT:   5 .comment      00000008 {{[0-9a-f]*}}
+# SEC-DEFAULT-NEXT:   6 .symtab       00000030
+# SEC-DEFAULT-NEXT:   7 .shstrtab     00000038
+# SEC-DEFAULT-NEXT:   8 .strtab       00000008
+
+## Now replace the symbol with '?' and check that results are the same.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.abc .ab?) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-DEFAULT %s
+
+## Now see how replacing '?' with '*' will consume whole abcd.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.abc .ab*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-ALL %s
+# SEC-ALL:      Sections:
+# SEC-ALL-NEXT: Idx Name          Size
+# SEC-ALL-NEXT:   0               00000000
+# SEC-ALL-NEXT:   1 .text         0000000c
+# SEC-ALL-NEXT:   2 .ad           00000004
+# SEC-ALL-NEXT:   3 .ag           00000004
+# SEC-ALL-NEXT:   4 .comment      00000008
+# SEC-ALL-NEXT:   5 .symtab       00000030
+# SEC-ALL-NEXT:   6 .shstrtab     00000032
+# SEC-ALL-NEXT:   7 .strtab       00000008
+
+## All sections started with .a are merged.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.a*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck -check-prefix=SEC-NO %s
+# SEC-NO: Sections:
+# SEC-NO-NEXT: Idx Name          Size
+# SEC-NO-NEXT:   0               00000000
+# SEC-NO-NEXT:   1 .text         00000014
+# SEC-NO-NEXT:   2 .comment      00000008
+# SEC-NO-NEXT:   3 .symtab       00000030
+# SEC-NO-NEXT:   4 .shstrtab     0000002a
+# SEC-NO-NEXT:   5 .strtab       00000008
+
+.text
+.section .abc,"ax",@progbits
+.long 0
+
+.text
+.section .abx,"ax",@progbits
+.long 0
+
+.text
+.section .abcd,"ax",@progbits
+.long 0
+
+.text
+.section .ad,"ax",@progbits
+.long 0
+
+.text
+.section .ag,"ax",@progbits
+.long 0
+
+
+.globl _start
+_start:
diff --git a/test/ELF/linkerscript/wildcards2.s b/test/ELF/linkerscript/wildcards2.s
new file mode 100644 (file)
index 0000000..5e8d6a3
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+## Check that aabc is not included in text.
+# RUN: echo "SECTIONS { \
+# RUN:      .text : { *(.abc) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: llvm-objdump -section-headers %t.out | \
+# RUN:   FileCheck %s
+# CHECK:      Sections:
+# CHECK-NEXT:  Idx Name          Size
+# CHECK-NEXT:    0               00000000
+# CHECK-NEXT:    1 .text         00000004
+# CHECK-NEXT:    2 aabc          00000004
+
+.text
+.section .abc,"ax",@progbits
+.long 0
+
+.text
+.section aabc,"ax",@progbits
+.long 0
+
+.globl _start
+_start:
diff --git a/test/ELF/lit.local.cfg b/test/ELF/lit.local.cfg
new file mode 100644 (file)
index 0000000..b93a36d
--- /dev/null
@@ -0,0 +1,2 @@
+config.suffixes = ['.test', '.s', '.ll']
+
diff --git a/test/ELF/llvm33-rela-outside-group.s b/test/ELF/llvm33-rela-outside-group.s
new file mode 100644 (file)
index 0000000..8e7e7c4
--- /dev/null
@@ -0,0 +1,11 @@
+// Input file generated with:
+// llvm33/llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %S/Inputs/llvm33-rela-outside-group.o
+//
+// RUN: ld.lld -shared %S/Inputs/llvm33-rela-outside-group.o %S/Inputs/llvm33-rela-outside-group.o
+
+       .global bar
+       .weak   _Z3fooIiEvv
+
+       .section        .text._Z3fooIiEvv,"axG",@progbits,_Z3fooIiEvv,comdat
+_Z3fooIiEvv:
+       callq   bar@PLT
diff --git a/test/ELF/local-dynamic.s b/test/ELF/local-dynamic.s
new file mode 100644 (file)
index 0000000..797a107
--- /dev/null
@@ -0,0 +1,94 @@
+// Check that local symbols are not inserted into dynamic table.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -shared -o %t1.so
+// RUN: llvm-readobj -t -dyn-symbols %t1.so | FileCheck %s
+// REQUIRES: x86
+
+// CHECK: Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: blah
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: goo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK: DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start@
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+
+blah:
+foo:
+goo:
+
+
diff --git a/test/ELF/local-got-pie.s b/test/ELF/local-got-pie.s
new file mode 100644 (file)
index 0000000..417f9d0
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -pie
+// RUN: llvm-readobj -s -r -d %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+.globl _start
+_start:
+ call foo@gotpcrel
+
+ .hidden foo
+ .global foo
+foo:
+ nop
+
+// 0x20B0 - 1001 - 5 = 4266
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT:   1000: {{.*}} callq 4267
+// DISASM:      foo:
+// DISASM-NEXT:   1005: {{.*}} nop
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x20B0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x20B0 R_X86_64_RELATIVE - 0x1005
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:      0x000000006FFFFFF9 RELACOUNT            1
diff --git a/test/ELF/local-got-shared.s b/test/ELF/local-got-shared.s
new file mode 100644 (file)
index 0000000..e4fd469
--- /dev/null
@@ -0,0 +1,36 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -s -r -d %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+bar:
+       call foo@gotpcrel
+
+        .hidden foo
+        .global foo
+foo:
+        nop
+
+// 0x20A0 - 0x1000 - 5 = 4251
+// DISASM:      bar:
+// DISASM-NEXT:   1000: {{.*}} callq 4251
+
+// DISASM:      foo:
+// DISASM-NEXT:   1005: {{.*}} nop
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x20A0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x20A0 R_X86_64_RELATIVE - 0x1005
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:      0x000000006FFFFFF9 RELACOUNT            1
diff --git a/test/ELF/local-got.s b/test/ELF/local-got.s
new file mode 100644 (file)
index 0000000..7e6ef9e
--- /dev/null
@@ -0,0 +1,48 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r -section-data %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+        .globl _start
+_start:
+       call bar@gotpcrel
+       call foo@gotpcrel
+
+        .global foo
+foo:
+        nop
+
+// 0x2020B0 - 0x201000 - 5 =  4251
+// 0x2020B8 - 0x201005 - 5 =  4254
+// DISASM:      _start:
+// DISASM-NEXT:   201000: {{.*}} callq 4267
+// DISASM-NEXT:   201005: {{.*}} callq 4270
+
+// DISASM:      foo:
+// DISASM-NEXT:   20100a: {{.*}} nop
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2020B0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// 0x20200a in little endian
+// CHECK-NEXT:   0000:  00000000 00000000 0A102000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2020B0 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/local-undefined-symbol.s b/test/ELF/local-undefined-symbol.s
new file mode 100644 (file)
index 0000000..34ef847
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t1
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK:     Symbols [
+# CHECK-NOT:  Name: foo
+
+.global _start
+_start:
+ jmp foo
+
+.local foo
diff --git a/test/ELF/local.s b/test/ELF/local.s
new file mode 100644 (file)
index 0000000..983d7ff
--- /dev/null
@@ -0,0 +1,92 @@
+// Check that symbol table is correctly populated with local symbols.
+// RUN: llvm-mc -save-temp-labels -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t1
+// RUN: llvm-readobj -t -s %t1 | FileCheck %s
+// REQUIRES: x86
+
+// Check that Info is equal to the number of local symbols.
+// CHECK:   Section {
+// CHECK:     Name: .symtab
+// CHECK-NEXT:     Type: SHT_SYMTAB
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info: 6
+
+// CHECK: Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: .Labs
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Absolute
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: abs
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Absolute
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: blah
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: goo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+
+blah:
+foo:
+goo:
+abs = 42
+.Labs = 43
diff --git a/test/ELF/lto/Inputs/archive-2.ll b/test/ELF/lto/Inputs/archive-2.ll
new file mode 100644 (file)
index 0000000..8236cfe
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/archive-3.ll b/test/ELF/lto/Inputs/archive-3.ll
new file mode 100644 (file)
index 0000000..ad8fb1e
--- /dev/null
@@ -0,0 +1,5 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/archive.ll b/test/ELF/lto/Inputs/archive.ll
new file mode 100644 (file)
index 0000000..71c1e4f
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/available-externally.ll b/test/ELF/lto/Inputs/available-externally.ll
new file mode 100644 (file)
index 0000000..b8583ea
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @zed() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/cache.ll b/test/ELF/lto/Inputs/cache.ll
new file mode 100644 (file)
index 0000000..0928902
--- /dev/null
@@ -0,0 +1,10 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @_start() {
+entry:
+  call void (...) @globalfunc()
+  ret i32 0
+}
+
+declare void @globalfunc(...)
diff --git a/test/ELF/lto/Inputs/comdat.s b/test/ELF/lto/Inputs/comdat.s
new file mode 100644 (file)
index 0000000..6f6e5ae
--- /dev/null
@@ -0,0 +1,5 @@
+    .section .text.f,"axG",@progbits,c,comdat
+    .globl foo
+
+foo:
+    retq
diff --git a/test/ELF/lto/Inputs/common.s b/test/ELF/lto/Inputs/common.s
new file mode 100644 (file)
index 0000000..e2cd9e6
--- /dev/null
@@ -0,0 +1 @@
+        .comm   a,8,4
diff --git a/test/ELF/lto/Inputs/common3.ll b/test/ELF/lto/Inputs/common3.ll
new file mode 100644 (file)
index 0000000..a4efc65
--- /dev/null
@@ -0,0 +1,3 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+@a = common hidden global i64 0, align 4
diff --git a/test/ELF/lto/Inputs/defsym-bar.ll b/test/ELF/lto/Inputs/defsym-bar.ll
new file mode 100644 (file)
index 0000000..748c7b2
--- /dev/null
@@ -0,0 +1,21 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @this_is_bar1()
+declare void @this_is_bar2()
+declare void @this_is_bar3()
+
+define hidden void @bar1() {
+  call void @this_is_bar1()
+  ret void
+}
+
+define hidden void @bar2() {
+  call void @this_is_bar2()
+  ret void
+}
+
+define hidden void @bar3() {
+  call void @this_is_bar3()
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/drop-debug-info.bc b/test/ELF/lto/Inputs/drop-debug-info.bc
new file mode 100644 (file)
index 0000000..f9c471f
Binary files /dev/null and b/test/ELF/lto/Inputs/drop-debug-info.bc differ
diff --git a/test/ELF/lto/Inputs/drop-linkage.ll b/test/ELF/lto/Inputs/drop-linkage.ll
new file mode 100644 (file)
index 0000000..0e3dc7a
--- /dev/null
@@ -0,0 +1,12 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+$foo = comdat any
+define linkonce void @foo() comdat {
+  ret void
+}
+
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/duplicated-name.ll b/test/ELF/lto/Inputs/duplicated-name.ll
new file mode 100644 (file)
index 0000000..78678c0
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f2() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/dynsym.s b/test/ELF/lto/Inputs/dynsym.s
new file mode 100644 (file)
index 0000000..a69f870
--- /dev/null
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+ret
diff --git a/test/ELF/lto/Inputs/internalize-exportdyn.ll b/test/ELF/lto/Inputs/internalize-exportdyn.ll
new file mode 100644 (file)
index 0000000..21ac358
--- /dev/null
@@ -0,0 +1,6 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define weak_odr void @bah() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/internalize-undef.ll b/test/ELF/lto/Inputs/internalize-undef.ll
new file mode 100644 (file)
index 0000000..71c1e4f
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/irmover-error.ll b/test/ELF/lto/Inputs/irmover-error.ll
new file mode 100644 (file)
index 0000000..86ed259
--- /dev/null
@@ -0,0 +1,6 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{ i32 1, !"foo", i32 2 }
+
+!llvm.module.flags = !{ !0 }
diff --git a/test/ELF/lto/Inputs/linkonce-odr.ll b/test/ELF/lto/Inputs/linkonce-odr.ll
new file mode 100644 (file)
index 0000000..0b38288
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define linkonce_odr void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/linkonce.ll b/test/ELF/lto/Inputs/linkonce.ll
new file mode 100644 (file)
index 0000000..a6738b3
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define linkonce void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/relocation-model-pic.ll b/test/ELF/lto/Inputs/relocation-model-pic.ll
new file mode 100644 (file)
index 0000000..e766054
--- /dev/null
@@ -0,0 +1,11 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foo = external global i32
+define i32 @main() {
+  %t = load i32, i32* @foo
+  ret i32 %t
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"PIC Level", i32 2}
diff --git a/test/ELF/lto/Inputs/resolution.s b/test/ELF/lto/Inputs/resolution.s
new file mode 100644 (file)
index 0000000..60b7870
--- /dev/null
@@ -0,0 +1,4 @@
+        .data
+        .global a
+a:
+        .long 9
diff --git a/test/ELF/lto/Inputs/save-temps.ll b/test/ELF/lto/Inputs/save-temps.ll
new file mode 100644 (file)
index 0000000..d6e6eb6
--- /dev/null
@@ -0,0 +1,6 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @bar() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/shared.s b/test/ELF/lto/Inputs/shared.s
new file mode 100644 (file)
index 0000000..ab79ed1
--- /dev/null
@@ -0,0 +1,7 @@
+.globl  printf
+.type printf, @function
+printf:
+
+.globl  puts
+.type puts, @function
+puts:
diff --git a/test/ELF/lto/Inputs/start-lib1.ll b/test/ELF/lto/Inputs/start-lib1.ll
new file mode 100644 (file)
index 0000000..9f42e6a
--- /dev/null
@@ -0,0 +1,8 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/start-lib2.ll b/test/ELF/lto/Inputs/start-lib2.ll
new file mode 100644 (file)
index 0000000..68b3c83
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @bar() {
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/thin1.ll b/test/ELF/lto/Inputs/thin1.ll
new file mode 100644 (file)
index 0000000..9302983
--- /dev/null
@@ -0,0 +1,12 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-scei-ps4"
+
+define i32 @foo(i32 %goo) {
+entry:
+  %goo.addr = alloca i32, align 4
+  store i32 %goo, i32* %goo.addr, align 4
+  %0 = load i32, i32* %goo.addr, align 4
+  %1 = load i32, i32* %goo.addr, align 4
+  %mul = mul nsw i32 %0, %1
+  ret i32 %mul
+}
diff --git a/test/ELF/lto/Inputs/thin2.ll b/test/ELF/lto/Inputs/thin2.ll
new file mode 100644 (file)
index 0000000..6cffbdc
--- /dev/null
@@ -0,0 +1,11 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-scei-ps4"
+
+define i32 @blah(i32 %meh) #0 {
+entry:
+  %meh.addr = alloca i32, align 4
+  store i32 %meh, i32* %meh.addr, align 4
+  %0 = load i32, i32* %meh.addr, align 4
+  %sub = sub nsw i32 %0, 48
+  ret i32 %sub
+}
diff --git a/test/ELF/lto/Inputs/thinlto.ll b/test/ELF/lto/Inputs/thinlto.ll
new file mode 100644 (file)
index 0000000..31c72ec
--- /dev/null
@@ -0,0 +1,7 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @g() {
+entry:
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/tls-mixed.s b/test/ELF/lto/Inputs/tls-mixed.s
new file mode 100644 (file)
index 0000000..b31ae3d
--- /dev/null
@@ -0,0 +1,4 @@
+.globl foo
+.section .tbss,"awT",@nobits
+foo:
+.long 0
diff --git a/test/ELF/lto/Inputs/type-merge.ll b/test/ELF/lto/Inputs/type-merge.ll
new file mode 100644 (file)
index 0000000..c316421
--- /dev/null
@@ -0,0 +1,8 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @zed() {
+  call void @bar()
+  ret void
+}
+declare void @bar()
diff --git a/test/ELF/lto/Inputs/type-merge2.ll b/test/ELF/lto/Inputs/type-merge2.ll
new file mode 100644 (file)
index 0000000..79fd1f8
--- /dev/null
@@ -0,0 +1,8 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%zed = type { i16 }
+define void @bar(%zed* %this)  {
+  store %zed* %this, %zed** null
+  ret void
+}
diff --git a/test/ELF/lto/Inputs/undef-mixed.s b/test/ELF/lto/Inputs/undef-mixed.s
new file mode 100644 (file)
index 0000000..2e4b7e1
--- /dev/null
@@ -0,0 +1,3 @@
+        .globl  bar
+bar:
+        retq
diff --git a/test/ELF/lto/Inputs/unnamed-addr-drop.ll b/test/ELF/lto/Inputs/unnamed-addr-drop.ll
new file mode 100644 (file)
index 0000000..b91bc8e
--- /dev/null
@@ -0,0 +1,4 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@foo = unnamed_addr constant i32 42
diff --git a/test/ELF/lto/Inputs/unnamed-addr-lib.s b/test/ELF/lto/Inputs/unnamed-addr-lib.s
new file mode 100644 (file)
index 0000000..e6ebce0
--- /dev/null
@@ -0,0 +1,6 @@
+        .protected foo
+        .global foo
+foo:
+
+        .global bar
+bar:
diff --git a/test/ELF/lto/Inputs/visibility.s b/test/ELF/lto/Inputs/visibility.s
new file mode 100644 (file)
index 0000000..db1379c
--- /dev/null
@@ -0,0 +1,8 @@
+        .global g
+g:
+        ret
+
+        .data
+        .global a
+a:
+        .long 41
diff --git a/test/ELF/lto/Inputs/wrap-bar.ll b/test/ELF/lto/Inputs/wrap-bar.ll
new file mode 100644 (file)
index 0000000..407ebfb
--- /dev/null
@@ -0,0 +1,14 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define hidden void @bar() {
+  ret void
+}
+
+define hidden void @__real_bar() {
+  ret void
+}
+
+define hidden void @__wrap_bar() {
+  ret void
+}
diff --git a/test/ELF/lto/archive-2.ll b/test/ELF/lto/archive-2.ll
new file mode 100644 (file)
index 0000000..6712d60
--- /dev/null
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-as %S/Inputs/archive-2.ll -o %t1.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+
+; CHECK:      Name: _start (
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @g() {
+  call void @_start()
+  ret void
+}
+
+declare void @_start()
+
diff --git a/test/ELF/lto/archive-3.ll b/test/ELF/lto/archive-3.ll
new file mode 100644 (file)
index 0000000..0322e41
--- /dev/null
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+; RUN: llvm-as %S/Inputs/archive-3.ll -o %t1.o
+; RUN: llvm-as %s -o %t2.o
+
+; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o  -o %t3 -save-temps
+; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s
+
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+; RUN: ld.lld -m elf_x86_64 %t.a %t1.o %t2.o  -o %t3 -save-temps
+; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s
+
+; CHECK: define internal void @foo() {
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/archive-no-index.ll b/test/ELF/lto/archive-no-index.ll
new file mode 100644 (file)
index 0000000..48cca0a
--- /dev/null
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; Tests that we suggest that LTO symbols missing from an archive index
+; may be the cause of undefined references, but only if we both
+; encountered an empty archive index and undefined references (to prevent
+; noisy false alarms).
+
+; RUN: llvm-as -o %t1.o %s
+; RUN: llvm-as -o %t2.o %S/Inputs/archive.ll
+
+; RUN: rm -f %t1.a %t2.a
+; RUN: llvm-ar crS %t1.a %t2.o
+; RUN: llvm-ar crs %t2.a %t2.o
+
+; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t1.a
+; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t2.a
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @f()
+
+define i32 @main() {
+  call void @f()
+  ret i32 0
+}
diff --git a/test/ELF/lto/archive.ll b/test/ELF/lto/archive.ll
new file mode 100644 (file)
index 0000000..b4d011f
--- /dev/null
@@ -0,0 +1,36 @@
+; REQUIRES: x86
+; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3 -shared
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared
+; RUN: llvm-readobj -t %t3 | FileCheck %s
+
+; CHECK:      Name: g (
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+; CHECK:      Name: f (
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @g() {
+  call void @f()
+  ret void
+}
+
+declare void @f()
+
diff --git a/test/ELF/lto/asmundef.ll b/test/ELF/lto/asmundef.ll
new file mode 100644 (file)
index 0000000..d03a5e3
--- /dev/null
@@ -0,0 +1,24 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t -save-temps
+; RUN: llvm-dis %t.0.4.opt.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm ".weak patatino"
+module asm ".equ patatino, foo"
+
+declare void @patatino()
+
+define void @foo() {
+  ret void
+}
+
+define void @_start() {
+  call void @patatino()
+  ret void
+}
+
+; CHECK: define void @foo
+
diff --git a/test/ELF/lto/available-externally.ll b/test/ELF/lto/available-externally.ll
new file mode 100644 (file)
index 0000000..315e710
--- /dev/null
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/available-externally.ll -o %t2.o
+; RUN: ld.lld %t1.o %t2.o -m elf_x86_64 -o %t.so -shared -save-temps
+; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo() {
+  call void @bar()
+  call void @zed()
+  ret void
+}
+define available_externally void @bar() {
+  ret void
+}
+define available_externally void @zed() {
+  ret void
+}
+
+; CHECK: define available_externally void @bar() {
+; CHECK: define void @zed() {
diff --git a/test/ELF/lto/bitcode-nodatalayout.ll b/test/ELF/lto/bitcode-nodatalayout.ll
new file mode 100644 (file)
index 0000000..5c4883a
--- /dev/null
@@ -0,0 +1,13 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: not ld.lld -m elf_x86_64 %t.o -o %t 2>&1 | FileCheck %s
+
+; CHECK: input module has no datalayout
+
+; This bitcode file has no datalayout.
+; Check that we error out producing a reasonable diagnostic.
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/cache.ll b/test/ELF/lto/cache.ll
new file mode 100644 (file)
index 0000000..6731f52
--- /dev/null
@@ -0,0 +1,32 @@
+; REQUIRES: x86
+
+; RUN: opt -module-hash -module-summary %s -o %t.o
+; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o
+
+; RUN: rm -Rf %t.cache && mkdir %t.cache
+; Create two files that would be removed by cache pruning due to age.
+; We should only remove files matching the pattern "llvmcache-*".
+; RUN: touch -t 197001011200 %t.cache/llvmcache-foo %t.cache/foo
+; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=1h -o %t3 %t2.o %t.o
+
+; Two cached objects, plus a timestamp file and "foo", minus the file we removed.
+; RUN: ls %t.cache | count 4
+
+; Create a file of size 64KB.
+; RUN: %python -c "print(' ' * 65536)" > %t.cache/llvmcache-foo
+
+; This should leave the file in place.
+; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=128k -o %t3 %t2.o %t.o
+; RUN: ls %t.cache | count 5
+
+; This should remove it.
+; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=32k -o %t3 %t2.o %t.o
+; RUN: ls %t.cache | count 4
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @globalfunc() #0 {
+entry:
+  ret void
+}
diff --git a/test/ELF/lto/codemodel.ll b/test/ELF/lto/codemodel.ll
new file mode 100644 (file)
index 0000000..cc12620
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %ts -mllvm -code-model=small
+; RUN: ld.lld -m elf_x86_64 %t.o -o %tl -mllvm -code-model=large
+; RUN: llvm-objdump -d %ts | FileCheck %s --check-prefix=CHECK-SMALL
+; RUN: llvm-objdump -d %tl | FileCheck %s --check-prefix=CHECK-LARGE
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@data = internal constant [0 x i32] []
+
+define i32* @_start() nounwind readonly {
+entry:
+; CHECK-SMALL-LABEL:  _start:
+; CHECK-SMALL: movl    $2097440, %eax
+; CHECK-LARGE-LABEL: _start:
+; CHECK-LARGE: movabsq $2097440, %rax
+    ret i32* getelementptr ([0 x i32], [0 x i32]* @data, i64 0, i64 0)
+}
diff --git a/test/ELF/lto/combined-lto-object-name.ll b/test/ELF/lto/combined-lto-object-name.ll
new file mode 100644 (file)
index 0000000..76564f9
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2 2>&1 | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @foo()
+define void @_start() {
+  call void @foo()
+  ret void
+}
+
+; CHECK: error: undefined symbol: foo
+; CHECK: >>> referenced by ld-temp.o
+; CHECK:                   {{.*}}:(_start)
diff --git a/test/ELF/lto/comdat.ll b/test/ELF/lto/comdat.ll
new file mode 100644 (file)
index 0000000..e1384d0
--- /dev/null
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+; CHECK:      Name: foo
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 1
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+$foo = comdat any
+define void @foo() comdat {
+  ret void
+}
+
diff --git a/test/ELF/lto/comdat2.ll b/test/ELF/lto/comdat2.ll
new file mode 100644 (file)
index 0000000..2831821
--- /dev/null
@@ -0,0 +1,41 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o -filetype=obj
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.o -o %t2.so -shared
+; RUN: llvm-readobj -t %t2.so | FileCheck %s --check-prefix=OTHER
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$c = comdat any
+
+define protected void @foo() comdat($c) {
+  ret void
+}
+
+; CHECK: Symbol {
+; CHECK:   Name: foo
+; CHECK-NEXT:   Value: 0x1000
+; CHECK-NEXT:   Size: 1
+; CHECK-NEXT:   Binding: Global
+; CHECK-NEXT:   Type: Function
+; CHECK-NEXT:   Other [
+; CHECK-NEXT:     STV_PROTECTED
+; CHECK-NEXT:   ]
+; CHECK-NEXT:   Section: .text
+; CHECK-NEXT: }
+
+; OTHER: Symbol {
+; OTHER:   Name: foo
+; OTHER-NEXT:   Value: 0x1000
+; OTHER-NEXT:   Size: 0
+; OTHER-NEXT:   Binding: Global
+; OTHER-NEXT:   Type: None
+; OTHER-NEXT:   Other [
+; OTHER-NEXT:     STV_PROTECTED
+; OTHER-NEXT:   ]
+; OTHER-NEXT:   Section: .text
+; OTHER-NEXT: }
diff --git a/test/ELF/lto/common.ll b/test/ELF/lto/common.ll
new file mode 100644 (file)
index 0000000..b020024
--- /dev/null
@@ -0,0 +1,31 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -s -t %t.so | FileCheck %s
+
+; CHECK:      Name: .bss
+; CHECK-NEXT: Type: SHT_NOBITS
+; CHECK-NEXT: Flags [
+; CHECK-NEXT:   SHF_ALLOC
+; CHECK-NEXT:   SHF_WRITE
+; CHECK-NEXT: ]
+; CHECK-NEXT: Address:
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Size: 8
+; CHECK-NEXT: Link: 0
+; CHECK-NEXT: Info: 0
+; CHECK-NEXT: AddressAlignment: 8
+
+; CHECK:      Name: a
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 8
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Object
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .bss
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@a = common global i32 0, align 8
diff --git a/test/ELF/lto/common2.ll b/test/ELF/lto/common2.ll
new file mode 100644 (file)
index 0000000..2345a20
--- /dev/null
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -m elf_x86_64 %t1.o -o %t -shared -save-temps
+; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
+; RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SHARED
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@a = common global i8 0, align 8
+; CHECK-DAG: @a = common global i8 0, align 8
+
+@b = common hidden global i32 0, align 4
+define i32 @f() {
+  %t = load i32, i32* @b, align 4
+  ret i32 %t
+}
+; CHECK-DAG: @b = internal global i32 0, align 4
+
+; SHARED: Symbol {
+; SHARED:   Name: a
+; SHARED-NEXT:   Value:
+; SHARED-NEXT:   Size: 1
+; SHARED-NEXT:   Binding: Global
+; SHARED-NEXT:   Type: Object
+; SHARED-NEXT:   Other: 0
+; SHARED-NEXT:   Section: .bss
+; SHARED-NEXT: }
diff --git a/test/ELF/lto/common3.ll b/test/ELF/lto/common3.ll
new file mode 100644 (file)
index 0000000..aea33f4
--- /dev/null
@@ -0,0 +1,15 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %S/Inputs/common3.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t -shared -save-temps
+; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+@a = common hidden global i32 0, align 8
+define i32 @f() {
+  %t = load i32, i32* @a, align 4
+  ret i32 %t
+}
+
+; CHECK: @a = internal global i64 0, align 8
diff --git a/test/ELF/lto/ctors.ll b/test/ELF/lto/ctors.ll
new file mode 100644 (file)
index 0000000..7fce645
--- /dev/null
@@ -0,0 +1,18 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: llvm-readobj -sections %t.so | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor, i8* null }]
+define void @ctor() {
+  call void asm "nop", ""()
+  ret void
+}
+
+; The llvm.global_ctors should end up producing constructors.
+; On x86-64 (linux) we should always emit .init_array and never .ctors.
+; CHECK: Name: .init_array
+; CHECK-NOT: Name: .ctors
diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll
new file mode 100644 (file)
index 0000000..2ce8570
--- /dev/null
@@ -0,0 +1,42 @@
+; REQUIRES: x86
+; LTO
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o
+; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3
+; RUN: llvm-objdump -d %t.so | FileCheck %s
+
+; ThinLTO
+; RUN: opt -module-summary %s -o %t.o
+; RUN: opt -module-summary %S/Inputs/defsym-bar.ll -o %t1.o
+; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3
+; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=THIN
+
+; Call to bar2() should not be inlined and should be routed to bar3()
+; Symbol bar3 should not be eliminated
+
+; CHECK:      foo:
+; CHECK-NEXT: pushq    %rax
+; CHECK-NEXT: callq
+; CHECK-NEXT: callq{{.*}}<bar3>
+; CHECK-NEXT: callq
+
+; THIN:       foo
+; THIN-NEXT:  pushq %rax
+; THIN-NEXT:  callq
+; THIN-NEXT:  callq{{.*}}<bar3>
+; THIN-NEXT:  popq %rax
+; THIN-NEXT:  jmp
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar1()
+declare void @bar2()
+declare void @bar3()
+
+define void @foo() {
+  call void @bar1()
+  call void @bar2()
+  call void @bar3()
+  ret void
+}
diff --git a/test/ELF/lto/discard-value-names.ll b/test/ELF/lto/discard-value-names.ll
new file mode 100644 (file)
index 0000000..f1e95fe
--- /dev/null
@@ -0,0 +1,24 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+
+; RUN: ld.lld -m elf_x86_64 -shared -save-temps %t.o -o %t2.o
+; RUN: llvm-dis < %t2.o.0.0.preopt.bc | FileCheck %s
+
+; CHECK: @GlobalValueName
+; CHECK: @foo(i32 %in)
+; CHECK: somelabel:
+; CHECK:  %GV = load i32, i32* @GlobalValueName
+; CHECK:  %add = add i32 %in, %GV
+; CHECK:  ret i32 %add
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@GlobalValueName = global i32 0
+
+define i32 @foo(i32 %in) {
+somelabel:
+  %GV = load i32, i32* @GlobalValueName
+  %add = add i32 %in, %GV
+  ret i32 %add
+}
diff --git a/test/ELF/lto/drop-debug-info.ll b/test/ELF/lto/drop-debug-info.ll
new file mode 100644 (file)
index 0000000..27c0260
--- /dev/null
@@ -0,0 +1,9 @@
+; REQUIRES: x86
+;
+; drop-debug-info.bc was created from "void f(void) {}" with clang 3.5 and
+; -gline-tables-only, so it contains old debug info.
+;
+; RUN: ld.lld -m elf_x86_64 -shared %p/Inputs/drop-debug-info.bc \
+; RUN: -disable-verify 2>&1 | FileCheck %s
+; CHECK: ignoring debug info with an invalid version (1) in {{.*}}drop-debug-info.bc
+
diff --git a/test/ELF/lto/drop-linkage.ll b/test/ELF/lto/drop-linkage.ll
new file mode 100644 (file)
index 0000000..1ff1796
--- /dev/null
@@ -0,0 +1,14 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; REQUIRES: x86
+; RUN: llc %s -o %t.o -filetype=obj
+; RUN: llvm-as %p/Inputs/drop-linkage.ll -o %t2.o
+; RUN: ld.lld %t.o %t2.o -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
+
+define void @foo() {
+  ret void
+}
+
+; CHECK: declare void @foo()
diff --git a/test/ELF/lto/duplicated-name.ll b/test/ELF/lto/duplicated-name.ll
new file mode 100644 (file)
index 0000000..b9e6c54
--- /dev/null
@@ -0,0 +1,15 @@
+; REQUIRES: x86
+; Cretae two archive with the same member name
+; RUN: rm -f %t1.a %t2.a
+; RUN: opt -module-summary %s -o %t.o
+; RUN: llvm-ar rcS %t1.a %t.o
+; RUN: opt -module-summary %p/Inputs/duplicated-name.ll -o %t.o
+; RUN: llvm-ar rcS %t2.a %t.o
+; RUN: ld.lld -m elf_x86_64 -shared -o %t.so -uf1 -uf2 %t1.a %t2.a
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f1() {
+  ret void
+}
diff --git a/test/ELF/lto/duplicated.ll b/test/ELF/lto/duplicated.ll
new file mode 100644 (file)
index 0000000..1567481
--- /dev/null
@@ -0,0 +1,14 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: not ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+; CHECK:      duplicate symbol: f
+; CHECK-NEXT: >>> defined in {{.*}}.o
+; CHECK-NEXT: >>> defined in {{.*}}.o
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f() {
+  ret void
+}
diff --git a/test/ELF/lto/dynamic-list.ll b/test/ELF/lto/dynamic-list.ll
new file mode 100644 (file)
index 0000000..0e950b3
--- /dev/null
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo "{ foo; };" > %t.list
+; RUN: ld.lld -m elf_x86_64 -o %t --dynamic-list %t.list -pie %t.o
+; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+; CHECK:      Name:     foo@
+; CHECK-NEXT: Value:    0x1010
+; CHECK-NEXT: Size:     1
+; CHECK-NEXT: Binding:  Global (0x1)
+; CHECK-NEXT: Type:     Function
+; CHECK-NEXT: Other:    0
+; CHECK-NEXT: Section:  .text
+; CHECK-NEXT: }
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/dynsym.ll b/test/ELF/lto/dynsym.ll
new file mode 100644 (file)
index 0000000..b2b4157
--- /dev/null
@@ -0,0 +1,30 @@
+; REQUIRES: x86
+; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t.o %p/Inputs/dynsym.s
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.so -o %t
+; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+; Check that we don't crash when gc'ing sections and printing the result.
+; RUN: ld.lld -m elf_x86_64 %t2.o %t.so --gc-sections --print-gc-sections \
+; RUN:   -o %t
+; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  call void @foo()
+  ret void
+}
+
+; CHECK:      Name: foo
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding:
+; CHECK-NEXT: Type:
+; CHECK-NEXT: Other:
+; CHECK-NEXT: Section: .text
+define void @foo() {
+  ret void
+}
diff --git a/test/ELF/lto/inline-asm.ll b/test/ELF/lto/inline-asm.ll
new file mode 100644 (file)
index 0000000..b6af6a5
--- /dev/null
@@ -0,0 +1,11 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo() {
+  call void asm "nop", ""()
+  ret void
+}
diff --git a/test/ELF/lto/internalize-basic.ll b/test/ELF/lto/internalize-basic.ll
new file mode 100644 (file)
index 0000000..43c1837
--- /dev/null
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define hidden void @foo() {
+  ret void
+}
+
+; Check that _start is not internalized.
+; CHECK: define void @_start()
+
+; Check that foo function is correctly internalized.
+; CHECK: define internal void @foo()
diff --git a/test/ELF/lto/internalize-exportdyn.ll b/test/ELF/lto/internalize-exportdyn.ll
new file mode 100644 (file)
index 0000000..2034a2b
--- /dev/null
@@ -0,0 +1,47 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/internalize-exportdyn.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t2 --export-dynamic -save-temps
+; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define void @foo() {
+  ret void
+}
+
+define hidden void @bar() {
+  ret void
+}
+
+define linkonce_odr void @zed() local_unnamed_addr {
+  ret void
+}
+
+define linkonce_odr void @zed2() unnamed_addr {
+  ret void
+}
+
+define linkonce_odr void @bah() {
+  ret void
+}
+
+define linkonce_odr void @baz() {
+  ret void
+}
+
+@use_baz = global void ()* @baz
+
+; Check what gets internalized.
+; CHECK: define void @_start()
+; CHECK: define void @foo()
+; CHECK: define internal void @bar()
+; CHECK: define internal void @zed()
+; CHECK: define internal void @zed2()
+; CHECK: define weak_odr void @bah()
+; CHECK: define weak_odr void @baz()
diff --git a/test/ELF/lto/internalize-llvmused.ll b/test/ELF/lto/internalize-llvmused.ll
new file mode 100644 (file)
index 0000000..253dcb2
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
+; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define hidden void @f() {
+  ret void
+}
+
+@llvm.used = appending global [1 x i8*] [ i8* bitcast (void ()* @f to i8*)]
+
+; Check that f is not internalized.
+; CHECK: define hidden void @f()
diff --git a/test/ELF/lto/internalize-undef.ll b/test/ELF/lto/internalize-undef.ll
new file mode 100644 (file)
index 0000000..f76528b
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/internalize-undef.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps
+; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @f()
+define void @_start() {
+  call void @f()
+  ret void
+}
+
+; CHECK: define internal void @f()
diff --git a/test/ELF/lto/internalize-version-script.ll b/test/ELF/lto/internalize-version-script.ll
new file mode 100644 (file)
index 0000000..c577e43
--- /dev/null
@@ -0,0 +1,22 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo "{ global: foo; local: *; };" > %t.script
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
+; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo() {
+  ret void
+}
+
+define void @bar() {
+  ret void
+}
+
+; Check that foo is not internalized.
+; CHECK: define void @foo()
+
+; Check that bar is correctly internalized.
+; CHECK: define internal void @bar()
diff --git a/test/ELF/lto/irmover-error.ll b/test/ELF/lto/irmover-error.ll
new file mode 100644 (file)
index 0000000..8b9836d
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: llvm-as -o %t1.bc %s
+; RUN: llvm-as -o %t2.bc %S/Inputs/irmover-error.ll
+; RUN: not ld.lld -m elf_x86_64 %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s
+
+; CHECK: linking module flags 'foo': IDs have conflicting values
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{ i32 1, !"foo", i32 1 }
+
+!llvm.module.flags = !{ !0 }
diff --git a/test/ELF/lto/linkage.ll b/test/ELF/lto/linkage.ll
new file mode 100644 (file)
index 0000000..5af9b32
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared
+; RUN: llvm-nm %t.so | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Should not encounter a duplicate symbol error for @.str
+@.str = private unnamed_addr constant [4 x i8] c"Hey\00", align 1
+
+; Should not encounter a duplicate symbol error for @llvm.global_ctors
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor, i8* null }]
+define internal void @ctor() {
+  ret void
+}
+
+; Should not try to merge a declaration into the combined module.
+declare i32 @llvm.ctpop.i32(i32)
+; CHECK-NOT: llvm.ctpop.i32
diff --git a/test/ELF/lto/linkonce-odr.ll b/test/ELF/lto/linkonce-odr.ll
new file mode 100644 (file)
index 0000000..4423351
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: llvm-as %p/Inputs/linkonce-odr.ll -o %t1.o
+; RUN: llc -relocation-model=pic %s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+declare void @f()
+
+define void @g() {
+  call void @f()
+  ret void
+}
+
+; Be sure that 'f' is kept and has weak_odr linkage.
+; CHECK: define weak_odr void @f()
diff --git a/test/ELF/lto/linkonce.ll b/test/ELF/lto/linkonce.ll
new file mode 100644 (file)
index 0000000..6dba6a3
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: llvm-as %p/Inputs/linkonce.ll -o %t1.o
+; RUN: llc -relocation-model=pic %s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+declare void @f()
+
+define void @g() {
+  call void @f()
+  ret void
+}
+
+; Be sure that 'f' is kept and has weak linkage.
+; CHECK: define weak void @f()
diff --git a/test/ELF/lto/lto-start.ll b/test/ELF/lto/lto-start.ll
new file mode 100644 (file)
index 0000000..e93eecf
--- /dev/null
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2
+; RUN: llvm-readobj -t %t2 | FileCheck %s
+
+; CHECK:      Format: ELF64-x86-64
+; CHECK-NEXT: Arch: x86_64
+; CHECK-NEXT: AddressSize: 64bit
+
+; CHECK:      Name: _start
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 1
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other:
+; CHECK-NEXT: Section: .text
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/ltopasses-basic.ll b/test/ELF/lto/ltopasses-basic.ll
new file mode 100644 (file)
index 0000000..0c4ad8b
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM
+; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @ctor, i8* null }]
+define void @ctor() {
+  ret void
+}
+
+; `@ctor` doesn't do anything and so the optimizer should kill it, leaving no ctors
+; CHECK: @llvm.global_ctors = appending global [0 x { i32, void ()*, i8* }] zeroinitializer
+
+; MLLVM: Pass Arguments:
diff --git a/test/ELF/lto/ltopasses-custom.ll b/test/ELF/lto/ltopasses-custom.ll
new file mode 100644 (file)
index 0000000..a48959a
--- /dev/null
@@ -0,0 +1,37 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps --lto-aa-pipeline=basic-aa \
+; RUN: --lto-newpm-passes=ipsccp -shared
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared
+; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
+; RUN: llvm-dis %t2.so.0.4.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @barrier() {
+  fence seq_cst
+  ret void
+}
+
+; IPSCCP won't remove the fence.
+; CHECK: define void @barrier() {
+; CHECK-NEXT: fence seq_cst
+; CHECK-NEXT: ret void
+
+; LowerAtomic will remove the fence.
+; ATOMIC: define void @barrier() {
+; ATOMIC-NEXT: ret void
+
+; Check that invalid passes are rejected gracefully.
+; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2.so \
+; RUN:   --lto-newpm-passes=iamnotapass -shared 2>&1 | \
+; RUN:   FileCheck %s --check-prefix=INVALID
+; INVALID: unable to parse pass pipeline description: iamnotapass
+
+; Check that invalid AA pipelines are rejected gracefully.
+; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2.so \
+; RUN:   --lto-newpm-passes=globaldce --lto-aa-pipeline=patatino \
+; RUN:   -shared 2>&1 | \
+; RUN:   FileCheck %s --check-prefix=INVALIDAA
+; INVALIDAA: unable to parse AA pipeline description: patatino
diff --git a/test/ELF/lto/metadata.ll b/test/ELF/lto/metadata.ll
new file mode 100644 (file)
index 0000000..2eaacaa
--- /dev/null
@@ -0,0 +1,15 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define weak void @foo(i32* %p) {
+  store i32 5, i32* %p, align 4, !tbaa !0
+  ret void
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"int", !2}
+!2 = !{!"Simple C/C++ TBAA"}
diff --git a/test/ELF/lto/mix-platforms.ll b/test/ELF/lto/mix-platforms.ll
new file mode 100644 (file)
index 0000000..3478caa
--- /dev/null
@@ -0,0 +1,10 @@
+; REQUIRES: x86
+; RUN: llvm-mc %p/Inputs/shared.s -o %t386.o -filetype=obj -triple=i386-pc-linux
+; RUN: ld.lld %t386.o -o %ti386.so -shared
+; RUN: llvm-as %s -o %tx64.o
+; RUN: not ld.lld %ti386.so %tx64.o -o %t 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: {{.*}}x64.o is incompatible with {{.*}}i386.so
diff --git a/test/ELF/lto/module-asm.ll b/test/ELF/lto/module-asm.ll
new file mode 100644 (file)
index 0000000..1389b9f
--- /dev/null
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t
+; RUN: llvm-nm %t | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm ".text"
+module asm ".globl foo"
+; CHECK: T foo
+module asm "foo: ret"
+
+declare void @foo()
+
+define void @_start() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/opt-level.ll b/test/ELF/lto/opt-level.ll
new file mode 100644 (file)
index 0000000..1065ca7
--- /dev/null
@@ -0,0 +1,30 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.o %s
+; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --lto-O0 %t.o
+; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: ld.lld -o %t2 -m elf_x86_64 -e main --lto-O2 %t.o
+; RUN: llvm-nm %t2 | FileCheck --check-prefix=CHECK-O2 %s
+; RUN: ld.lld -o %t2a -m elf_x86_64 -e main %t.o
+; RUN: llvm-nm %t2a | FileCheck --check-prefix=CHECK-O2 %s
+
+; Reject invalid optimization levels.
+; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O6 %t.o 2>&1 | \
+; RUN:   FileCheck --check-prefix=INVALID %s
+; INVALID: invalid optimization level for LTO: 6
+; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \
+; RUN:   FileCheck --check-prefix=INVALIDNEGATIVE %s
+; INVALIDNEGATIVE: invalid optimization level for LTO: -1
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK-O0: foo
+; CHECK-O2-NOT: foo
+define internal void @foo() {
+  ret void
+}
+
+define void @main() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/opt-remarks.ll b/test/ELF/lto/opt-remarks.ll
new file mode 100644 (file)
index 0000000..e29cc72
--- /dev/null
@@ -0,0 +1,69 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+
+; RUN: rm -f %t.yaml
+; RUN: ld.lld --opt-remarks-filename %t.yaml %t.o -o %t -shared -save-temps
+; RUN: llvm-dis %t.0.4.opt.bc -o - | FileCheck %s
+; RUN: ld.lld --opt-remarks-with-hotness --opt-remarks-filename %t.hot.yaml \
+; RUN:  %t.o -o %t -shared
+; RUN: cat %t.yaml | FileCheck %s -check-prefix=YAML
+; RUN: cat %t.hot.yaml | FileCheck %s -check-prefix=YAML-HOT
+
+; Check that @tinkywinky is inlined after optimizations.
+; CHECK-LABEL: define i32 @main
+; CHECK-NEXT:  %a.i = call i32 @patatino()
+; CHECK-NEXT:  ret i32 %a.i
+; CHECK-NEXT: }
+
+; YAML: --- !Analysis
+; YAML-NEXT: Pass:            inline
+; YAML-NEXT: Name:            CanBeInlined
+; YAML-NEXT: Function:        main
+; YAML-NEXT: Args:
+; YAML-NEXT:   - Callee:          tinkywinky
+; YAML-NEXT:   - String:          ' can be inlined into '
+; YAML-NEXT:   - Caller:          main
+; YAML-NEXT:   - String:          ' with cost='
+; YAML-NEXT:   - Cost:            '0'
+; YAML-NEXT:   - String:          ' (threshold='
+; YAML-NEXT:   - Threshold:       '337'
+; YAML-NEXT:   - String:          ')'
+; YAML-NEXT: ...
+; YAML-NEXT: --- !Passed
+; YAML-NEXT: Pass:            inline
+; YAML-NEXT: Name:            Inlined
+; YAML-NEXT: Function:        main
+; YAML-NEXT: Args:
+; YAML-NEXT:   - Callee:          tinkywinky
+; YAML-NEXT:   - String:          ' inlined into '
+; YAML-NEXT:   - Caller:          main
+; YAML-NEXT: ...
+
+; YAML-HOT: ...
+; YAML-HOT: --- !Passed
+; YAML-HOT: Pass:            inline
+; YAML-HOT-NEXT: Name:            Inlined
+; YAML-HOT-NEXT: Function:        main
+; YAML-HOT-NEXT: Hotness:         300
+; YAML-HOT-NEXT: Args:
+; YAML-HOT-NEXT:   - Callee:          tinkywinky
+; YAML-HOT-NEXT:   - String:          ' inlined into '
+; YAML-HOT-NEXT:   - Caller:          main
+; YAML-HOT-NEXT: ...
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-scei-ps4"
+
+declare i32 @patatino()
+
+define i32 @tinkywinky() {
+  %a = call i32 @patatino()
+  ret i32 %a
+}
+
+define i32 @main() !prof !0 {
+  %i = call i32 @tinkywinky()
+  ret i32 %i
+}
+
+!0 = !{!"function_entry_count", i64 300}
diff --git a/test/ELF/lto/parallel-internalize.ll b/test/ELF/lto/parallel-internalize.ll
new file mode 100644 (file)
index 0000000..da5bdc6
--- /dev/null
@@ -0,0 +1,59 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.bc %s
+; RUN: rm -f %t.lto.o %t1.lto.o
+; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc \
+; RUN:   -e foo --lto-O0
+; RUN: llvm-readobj -t -dyn-symbols %t | FileCheck %s
+; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
+
+; CHECK:      Symbols [
+; CHECK-NEXT:   Symbol {
+; CHECK-NEXT:     Name:  (0)
+; CHECK-NEXT:     Value: 0x0
+; CHECK-NEXT:     Size: 0
+; CHECK-NEXT:     Binding: Local (0x0)
+; CHECK-NEXT:     Type: None (0x0)
+; CHECK-NEXT:     Other: 0
+; CHECK-NEXT:     Section: Undefined (0x0)
+; CHECK-NEXT:   }
+; CHECK-NEXT:   Symbol {
+; CHECK-NEXT:     Name: bar
+; CHECK-NEXT:     Value: 0x201010
+; CHECK-NEXT:     Size: 8
+; CHECK-NEXT:     Binding: Local (0x0)
+; CHECK-NEXT:     Type: Function (0x2)
+; CHECK-NEXT:     Other [ (0x2)
+; CHECK-NEXT:       STV_HIDDEN (0x2)
+; CHECK-NEXT:     ]
+; CHECK-NEXT:     Section: .text (0x2)
+; CHECK-NEXT:   }
+; CHECK-NEXT:   Symbol {
+; CHECK-NEXT:     Name: foo
+; CHECK-NEXT:     Value: 0x201000
+; CHECK-NEXT:     Size: 8
+; CHECK-NEXT:     Binding: Global (0x1)
+; CHECK-NEXT:     Type: Function (0x2)
+; CHECK-NEXT:     Other: 0
+; CHECK-NEXT:     Section: .text (0x2)
+; CHECK-NEXT:   }
+; CHECK-NEXT: ]
+; CHECK-NEXT: DynamicSymbols [
+; CHECK-NEXT: ]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK0: U bar
+; CHECK0: T foo
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK1: T bar
+; CHECK1: U foo
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/parallel.ll b/test/ELF/lto/parallel.ll
new file mode 100644 (file)
index 0000000..a1c15af
--- /dev/null
@@ -0,0 +1,25 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %t.bc %s
+; RUN: rm -f %t.lto.o %t1.lto.o
+; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc -shared
+; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK0-NOT: bar
+; CHECK0: T foo
+; CHECK0-NOT: bar
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK1-NOT: foo
+; CHECK1: T bar
+; CHECK1-NOT: foo
+define void @bar() {
+  call void @foo()
+  ret void
+}
diff --git a/test/ELF/lto/pic.ll b/test/ELF/lto/pic.ll
new file mode 100644 (file)
index 0000000..abc514d
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t.so -shared
+; RUN: llvm-readobj -r %t.so | FileCheck %s
+
+; CHECK:      Relocations [
+; CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+; CHECK-NEXT:     R_X86_64_JUMP_SLOT bar 0x0
+; CHECK-NEXT:   }
+; CHECK-NEXT: ]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+define void @foo() {
+  call void @bar()
+  ret void
+}
diff --git a/test/ELF/lto/relax-relocs.ll b/test/ELF/lto/relax-relocs.ll
new file mode 100644 (file)
index 0000000..8e8d9d1
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 -save-temps -shared %t.o -o %t.so
+; RUN: llvm-readobj -r %t.so.lto.o | FileCheck %s
+
+; Test that we produce R_X86_64_REX_GOTPCRELX instead of R_X86_64_GOTPCREL
+; CHECK: R_X86_64_REX_GOTPCRELX foo
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foo = external global i32
+define i32 @bar() {
+  %t = load i32, i32* @foo
+  ret i32 %t
+}
diff --git a/test/ELF/lto/relocation-model.ll b/test/ELF/lto/relocation-model.ll
new file mode 100644 (file)
index 0000000..78334dd
--- /dev/null
@@ -0,0 +1,46 @@
+; REQUIRES: x86
+
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/relocation-model-pic.ll -o %t.pic.o
+
+;; Non-PIC source.
+
+; RUN: ld.lld %t.o -o %t-out -save-temps -shared
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC
+
+; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC
+
+; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC
+
+; RUN: ld.lld %t.o -o %t-out -save-temps -r --export-dynamic
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC
+
+
+;; PIC source.
+
+; RUN: ld.lld %t.pic.o -o %t-out -save-temps -shared
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC
+
+; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC
+
+; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC
+
+; RUN: ld.lld %t.pic.o -o %t-out -save-temps -r --export-dynamic
+; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC
+
+
+; PIC: R_X86_64_REX_GOTPCRELX foo
+; STATIC: R_X86_64_PC32 foo
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foo = external global i32
+define i32 @main() {
+  %t = load i32, i32* @foo
+  ret i32 %t
+}
diff --git a/test/ELF/lto/resolution.ll b/test/ELF/lto/resolution.ll
new file mode 100644 (file)
index 0000000..b3fcf1d
--- /dev/null
@@ -0,0 +1,27 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -s --section-data %t.so | FileCheck %s
+
+; CHECK:      Name: .data
+; CHECK-NEXT: Type: SHT_PROGBITS
+; CHECK-NEXT: Flags [
+; CHECK-NEXT:   SHF_ALLOC
+; CHECK-NEXT:   SHF_WRITE
+; CHECK-NEXT: ]
+; CHECK-NEXT: Address:
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Size: 4
+; CHECK-NEXT: Link: 0
+; CHECK-NEXT: Info: 0
+; CHECK-NEXT: AddressAlignment: 1
+; CHECK-NEXT: EntrySize: 0
+; CHECK-NEXT: SectionData (
+; CHECK-NEXT:   0000: 09000000 |{{.*}}|
+; CHECK-NEXT: )
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@a = weak global i32 8
diff --git a/test/ELF/lto/save-temps.ll b/test/ELF/lto/save-temps.ll
new file mode 100644 (file)
index 0000000..f7af99e
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: cd %T
+; RUN: rm -f a.out a.out.lto.bc a.out.lto.o
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/save-temps.ll -o %t2.o
+; RUN: ld.lld -shared -m elf_x86_64 %t.o %t2.o -save-temps
+; RUN: llvm-nm a.out | FileCheck %s
+; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s
+; RUN: llvm-nm a.out.lto.o | FileCheck %s
+; RUN: llvm-dis a.out.0.0.preopt.bc
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo() {
+  ret void
+}
+
+; CHECK: T bar
+; CHECK: T foo
diff --git a/test/ELF/lto/shlib-undefined.ll b/test/ELF/lto/shlib-undefined.ll
new file mode 100644 (file)
index 0000000..0250ed7
--- /dev/null
@@ -0,0 +1,27 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo .global __progname > %t2.s
+; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
+; RUN: ld.lld -shared %t2.o -o %t2.so
+; RUN: ld.lld -o %t %t.o %t2.so
+; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+; CHECK:      Name:     __progname@
+; CHECK-NEXT: Value:    0x201010
+; CHECK-NEXT: Size:     1
+; CHECK-NEXT: Binding:  Global (0x1)
+; CHECK-NEXT: Type:     Function
+; CHECK-NEXT: Other:    0
+; CHECK-NEXT: Section:  .text
+; CHECK-NEXT: }
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+define void @__progname() {
+  ret void
+}
diff --git a/test/ELF/lto/start-lib.ll b/test/ELF/lto/start-lib.ll
new file mode 100644 (file)
index 0000000..ec73954
--- /dev/null
@@ -0,0 +1,27 @@
+; REQUIRES: x86
+;
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/start-lib1.ll -o %t2.o
+; RUN: llvm-as %p/Inputs/start-lib2.ll -o %t3.o
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o %t2.o %t3.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST1 %s
+; TEST1: Name: bar
+; TEST1: Name: foo
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 -u bar %t1.o --start-lib %t2.o %t3.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST2 %s
+; TEST2: Name: bar
+; TEST2-NOT: Name: foo
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o --start-lib %t2.o %t3.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST3 %s
+; TEST3-NOT: Name: bar
+; TEST3-NOT: Name: foo
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  ret void
+}
diff --git a/test/ELF/lto/thin-archivecollision.ll b/test/ELF/lto/thin-archivecollision.ll
new file mode 100644 (file)
index 0000000..554c2b0
--- /dev/null
@@ -0,0 +1,37 @@
+; REQUIRES: x86
+; RUN: opt -module-summary %s -o %t.o
+; RUN: mkdir -p %t1 %t2
+; RUN: opt -module-summary %p/Inputs/thin1.ll -o %t1/t.coll.o
+; RUN: opt -module-summary %p/Inputs/thin2.ll -o %t2/t.coll.o
+
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1/t.coll.o %t2/t.coll.o
+; RUN: ld.lld %t.o %t.a -o %t
+; RUN: llvm-nm %t | FileCheck %s
+
+; Check without a archive symbol table
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcS %t.a %t1/t.coll.o %t2/t.coll.o
+; RUN: ld.lld %t.o %t.a -o %t
+; RUN: llvm-nm %t | FileCheck %s
+
+; Check we handle this case correctly even in presence of --whole-archive.
+; RUN: ld.lld %t.o --whole-archive %t.a -o %t
+; RUN: llvm-nm %t | FileCheck %s
+
+; CHECK: T _start
+; CHECK: T blah
+; CHECK: T foo
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-scei-ps4"
+
+define i32 @_start() {
+entry:
+  %call = call i32 @foo(i32 23)
+  %call1 = call i32 @blah(i32 37)
+  ret i32 0
+}
+
+declare i32 @foo(i32) #1
+declare i32 @blah(i32) #1
diff --git a/test/ELF/lto/thinlto.ll b/test/ELF/lto/thinlto.ll
new file mode 100644 (file)
index 0000000..99dd191
--- /dev/null
@@ -0,0 +1,37 @@
+; REQUIRES: x86
+; Basic ThinLTO tests.
+; RUN: opt -module-summary %s -o %t.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
+
+; First force single-threaded mode
+; RUN: rm -f %t.lto.o %t1.lto.o
+; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t.o %t2.o -o %t
+; RUN: llvm-nm %t.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t1.lto.o | FileCheck %s --check-prefix=NM2
+
+; Next force multi-threaded mode
+; RUN: rm -f %t2.lto.o %t21.lto.o
+; RUN: ld.lld -save-temps --thinlto-jobs=2 -shared %t.o %t2.o -o %t2
+; RUN: llvm-nm %t2.lto.o | FileCheck %s --check-prefix=NM1
+; RUN: llvm-nm %t21.lto.o | FileCheck %s --check-prefix=NM2
+
+; NM1: T f
+; NM1-NOT: U g
+
+; NM2: T g
+
+; Then check without --thinlto-jobs (which currently default to hardware_concurrency)
+; We just check that we don't crash or fail (as it's not sure which tests are
+; stable on the final output file itself.
+; RUN: ld.lld -shared %t.o %t2.o -o %t2
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @g(...)
+
+define void @f() {
+entry:
+  call void (...) @g()
+  ret void
+}
diff --git a/test/ELF/lto/timepasses.ll b/test/ELF/lto/timepasses.ll
new file mode 100644 (file)
index 0000000..5c893e6
--- /dev/null
@@ -0,0 +1,15 @@
+; We use lld -flavor gnu because llvm-lit will append --full-shutdown to
+; the ld.lld invocation.
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: lld -flavor gnu %t.o -o %t.so -shared -mllvm -time-passes 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @patatino() {
+  ret void
+}
+
+; We should get the output of -time-passes even when --full-shutdown is not specified.
+; CHECK: Total Execution Time
diff --git a/test/ELF/lto/tls-mixed.ll b/test/ELF/lto/tls-mixed.ll
new file mode 100644 (file)
index 0000000..524bb4f
--- /dev/null
@@ -0,0 +1,10 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc %p/Inputs/tls-mixed.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -shared
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Should not encounter TLS-ness mismatch for @foo
+@foo = external thread_local global i32, align 4
diff --git a/test/ELF/lto/tls-preserve.ll b/test/ELF/lto/tls-preserve.ll
new file mode 100644 (file)
index 0000000..8aebcb7
--- /dev/null
@@ -0,0 +1,25 @@
+; TLS attribute needs to be preserved.
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: ld.lld -shared %t1.o -m elf_x86_64 -o %t1
+; RUN: llvm-readobj -t %t1 | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@tsp_int = thread_local global i32 1
+
+define void @_start() {
+  %val = load i32, i32* @tsp_int
+  ret void
+}
+
+; CHECK: Symbol {
+; CHECK:   Name: tsp_int
+; CHECK-NEXT:   Value: 0x0
+; CHECK-NEXT:   Size: 4
+; CHECK-NEXT:   Binding: Global
+; CHECK-NEXT:   Type: TLS
+; CHECK-NEXT:   Other: 0
+; CHECK-NEXT:   Section: .tdata
+; CHECK-NEXT: }
diff --git a/test/ELF/lto/type-merge.ll b/test/ELF/lto/type-merge.ll
new file mode 100644 (file)
index 0000000..d6f196d
--- /dev/null
@@ -0,0 +1,26 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/type-merge.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -shared -save-temps
+; RUN: llvm-dis < %t.0.0.preopt.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo()  {
+  call void @bar(i8* null)
+  ret void
+}
+declare void @bar(i8*)
+
+; CHECK:      define void @foo() {
+; CHECK-NEXT:   call void @bar(i8* null)
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+; CHECK: declare void @bar(i8*)
+
+; CHECK:      define void @zed() {
+; CHECK-NEXT:   call void bitcast (void (i8*)* @bar to void ()*)()
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
diff --git a/test/ELF/lto/type-merge2.ll b/test/ELF/lto/type-merge2.ll
new file mode 100644 (file)
index 0000000..6ebbf77
--- /dev/null
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/type-merge2.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared -save-temps
+; RUN: llvm-dis %t.so.0.0.preopt.bc -o - | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%zed = type { i8 }
+define void @foo()  {
+  call void @bar(%zed* null)
+  ret void
+}
+declare void @bar(%zed*)
+
+; CHECK:      %zed = type { i8 }
+; CHECK-NEXT: %zed.0 = type { i16 }
+
+; CHECK:      define void @foo() {
+; CHECK-NEXT:   call void bitcast (void (%zed.0*)* @bar to void (%zed*)*)(%zed* null)
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+; CHECK:      define void @bar(%zed.0* %this) {
+; CHECK-NEXT:   store %zed.0* %this, %zed.0** null
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
diff --git a/test/ELF/lto/undef-mixed.ll b/test/ELF/lto/undef-mixed.ll
new file mode 100644 (file)
index 0000000..0fff578
--- /dev/null
@@ -0,0 +1,22 @@
+; REQUIRES: x86
+; RUN: llvm-mc %p/Inputs/undef-mixed.s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld %t2.o %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+; CHECK:      Name: bar
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .text
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+define void @foo() {
+  call void @bar()
+  ret void
+}
diff --git a/test/ELF/lto/undef-weak.ll b/test/ELF/lto/undef-weak.ll
new file mode 100644 (file)
index 0000000..215978a
--- /dev/null
@@ -0,0 +1,29 @@
+; REQUIRES: x86
+
+; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o
+; RUN: rm -f %t.a
+; RUN: llvm-ar rcs %t.a %t1.o
+
+
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t2.o -o %t2.so %t.a -shared
+; RUN: llvm-readobj -t %t2.so | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare extern_weak void @f()
+define void @foo() {
+  call void @f()
+  ret void
+}
+
+; We should not fetch the archive member.
+
+; CHECK:      Name: f ({{.*}})
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Weak
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Undefined
+
diff --git a/test/ELF/lto/undef.ll b/test/ELF/lto/undef.ll
new file mode 100644 (file)
index 0000000..41da610
--- /dev/null
@@ -0,0 +1,20 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @bar()
+define void @foo() {
+  call void @bar()
+  ret void
+}
+
+; CHECK:      Name: bar
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: Undefined
diff --git a/test/ELF/lto/undefined-puts.ll b/test/ELF/lto/undefined-puts.ll
new file mode 100644 (file)
index 0000000..d136303
--- /dev/null
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-mc %p/Inputs/shared.s -o %t1.o -filetype=obj -triple=x86_64-unknown-linux
+; RUN: ld.lld %t1.o -o %t1.so -shared
+; RUN: llvm-as %s -o %t2.o
+; RUN: ld.lld %t1.so %t2.o -m elf_x86_64 -o %t
+; RUN: llvm-readobj -dyn-symbols -dyn-relocations %t | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@.str = private unnamed_addr constant [6 x i8] c"blah\0A\00", align 1
+
+define i32 @_start() {
+  %str = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0))
+  ret i32 0
+}
+
+declare i32 @printf(i8*, ...)
+
+; Check that puts symbol is present in the dynamic symbol table and
+; there's a relocation for it.
+; CHECK: Dynamic Relocations {
+; CHECK-NEXT:  0x202018 R_X86_64_JUMP_SLOT puts 0x0
+; CHECK-NEXT: }
+
+; CHECK: DynamicSymbols [
+; CHECK: Symbol {
+; CHECK:    Name: puts@
diff --git a/test/ELF/lto/unnamed-addr-comdat.ll b/test/ELF/lto/unnamed-addr-comdat.ll
new file mode 100644 (file)
index 0000000..29a5941
--- /dev/null
@@ -0,0 +1,12 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+$foo = comdat any
+@foo = linkonce_odr unnamed_addr constant i32 42, comdat
+
+; CHECK: @foo = internal unnamed_addr constant i32 42, comdat
diff --git a/test/ELF/lto/unnamed-addr-drop.ll b/test/ELF/lto/unnamed-addr-drop.ll
new file mode 100644 (file)
index 0000000..e827cbb
--- /dev/null
@@ -0,0 +1,13 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %S/Inputs/unnamed-addr-drop.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@foo = weak constant i32 41
+
+; Check that unnamed_addr is dropped during the merge.
+; CHECK: @foo = constant i32 42
diff --git a/test/ELF/lto/unnamed-addr-lib.ll b/test/ELF/lto/unnamed-addr-lib.ll
new file mode 100644 (file)
index 0000000..c2bc601
--- /dev/null
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-mc %p/Inputs/unnamed-addr-lib.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+; RUN: ld.lld %t2.o -shared -o %t2.so
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.so -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
+
+; This documents a small limitation of lld's internalization logic. We decide
+; that bar should be in the symbol table because if it is it will preempt the
+; one in the shared library.
+; We could add one extra bit for ODR so that we know that preemption is not
+; necessary, but that is probably not worth it.
+
+; CHECK: @foo = internal unnamed_addr constant i8 42
+; CHECK: @bar = weak_odr unnamed_addr constant i8 42
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@foo = linkonce_odr unnamed_addr constant i8 42
+@bar = linkonce_odr unnamed_addr constant i8 42
diff --git a/test/ELF/lto/unnamed-addr.ll b/test/ELF/lto/unnamed-addr.ll
new file mode 100644 (file)
index 0000000..56fe148
--- /dev/null
@@ -0,0 +1,15 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -shared
+; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@a = internal unnamed_addr constant i8 42
+
+define i8* @f() {
+  ret i8* @a
+}
+
+; CHECK: @a = internal unnamed_addr constant i8 42
diff --git a/test/ELF/lto/verify-invalid.ll b/test/ELF/lto/verify-invalid.ll
new file mode 100644 (file)
index 0000000..16d6a3e
--- /dev/null
@@ -0,0 +1,17 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN:   2>&1 | FileCheck -check-prefix=DEFAULT %s
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \
+; RUN:   -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}
+
+; -disable-verify should disable the verification of bitcode.
+; DEFAULT:     Pass Arguments: {{.*}} -verify {{.*}} -verify
+; DISABLE-NOT: Pass Arguments: {{.*}} -verify {{.*}} -verify
diff --git a/test/ELF/lto/version-script.ll b/test/ELF/lto/version-script.ll
new file mode 100644 (file)
index 0000000..c43b443
--- /dev/null
@@ -0,0 +1,50 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: echo "VERSION_1.0{ global: foo; local: *; }; VERSION_2.0{ global: bar; local: *; };" > %t.script
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
+; RUN: llvm-dis < %t2.0.0.preopt.bc | FileCheck %s
+; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo() {
+  ret void
+}
+
+define void @bar() {
+  ret void
+}
+
+; CHECK: define void @foo()
+; CHECK: define void @bar()
+
+; DSO: DynamicSymbols [
+; DSO:   Symbol {
+; DSO:     Name: @ (0)
+; DSO:     Value: 0x0
+; DSO:     Size: 0
+; DSO:     Binding: Local
+; DSO:     Type: None
+; DSO:     Other: 0
+; DSO:     Section: Undefined
+; DSO:   }
+; DSO:   Symbol {
+; DSO:     Name: foo@@VERSION_1.0
+; DSO:     Value: 0x1000
+; DSO:     Size: 1
+; DSO:     Binding: Global
+; DSO:     Type: Function
+; DSO:     Other: 0
+; DSO:     Section: .text
+; DSO:   }
+; DSO:   Symbol {
+; DSO:     Name: bar@@VERSION_2.0
+; DSO:     Value: 0x1010
+; DSO:     Size: 1
+; DSO:     Binding: Global
+; DSO:     Type: Function
+; DSO:     Other: 0
+; DSO:     Section: .text
+; DSO:   }
+; DSO: ]
diff --git a/test/ELF/lto/visibility.ll b/test/ELF/lto/visibility.ll
new file mode 100644 (file)
index 0000000..9acc0e2
--- /dev/null
@@ -0,0 +1,35 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2.o -filetype=obj
+; RUN: ld.lld %t1.o %t2.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+; CHECK:      Name: g
+; CHECK-NEXT: Value: 0x1000
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other [ (0x2)
+; CHECK-NEXT:   STV_HIDDEN
+; CHECK-NEXT: ]
+; CHECK-NEXT: Section: .text
+
+; CHECK:      Name: a
+; CHECK-NEXT: Value: 0x2000
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: None
+; CHECK-NEXT: Other [ (0x2)
+; CHECK-NEXT:   STV_HIDDEN
+; CHECK-NEXT: ]
+; CHECK-NEXT: Section: .data
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare hidden void @g()
+define void @f() {
+  call void @g()
+  ret void
+}
+@a = weak hidden global i32 42
diff --git a/test/ELF/lto/weak.ll b/test/ELF/lto/weak.ll
new file mode 100644 (file)
index 0000000..381ef7a
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared
+; RUN: llvm-readobj -t %t.so | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define weak void @f() {
+  ret void
+}
+
+; CHECK:      Name: f
+; CHECK-NEXT: Value: 0x1000
+; CHECK-NEXT: Size: 1
+; CHECK-NEXT: Binding: Weak
diff --git a/test/ELF/lto/wrap-1.ll b/test/ELF/lto/wrap-1.ll
new file mode 100644 (file)
index 0000000..1dd9139
--- /dev/null
@@ -0,0 +1,42 @@
+; REQUIRES: x86
+; LTO
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps
+; RUN: llvm-readobj -t %t.out | FileCheck %s
+; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s
+
+; ThinLTO
+; RUN: opt -module-summary %s -o %t.o
+; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps
+; RUN: llvm-readobj -t %t.out | FileCheck %s
+; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s
+
+; CHECK:      Name: __wrap_bar
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size:
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+
+; Make sure that the 'r' (linker redefined) bit is set for bar and __wrap_bar
+; in the resolutions file.
+; RESOLS: ,bar,r
+; RESOLS: ,__wrap_bar,px
+; RESOLS: ,__real_bar,pxr
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+
+define void @_start() {
+  call void @bar()
+  ret void
+}
+
+define void @__wrap_bar() {
+  ret void
+}
+
+define void @__real_bar() {
+  ret void
+}
diff --git a/test/ELF/lto/wrap-2.ll b/test/ELF/lto/wrap-2.ll
new file mode 100644 (file)
index 0000000..06ef406
--- /dev/null
@@ -0,0 +1,50 @@
+; REQUIRES: x86
+; LTO
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o
+; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar
+; RUN: llvm-objdump -d %t.so | FileCheck %s
+; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s
+
+; ThinLTO
+; RUN: opt -module-summary %s -o %t.o
+; RUN: opt -module-summary %S/Inputs/wrap-bar.ll -o %t1.o
+; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar
+; RUN: llvm-objdump -d %t.so | FileCheck %s -check-prefix=THIN
+; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s
+
+; Make sure that calls in foo() are not eliminated and that bar is
+; routed to __wrap_bar and __real_bar is routed to bar.
+
+; CHECK:      foo:
+; CHECK-NEXT: pushq    %rax
+; CHECK-NEXT: callq{{.*}}<__wrap_bar>
+; CHECK-NEXT: callq{{.*}}<bar>
+
+; THIN:      foo:
+; THIN-NEXT: pushq     %rax
+; THIN-NEXT: callq{{.*}}<__wrap_bar>
+; THIN-NEXT: popq  %rax
+; THIN-NEXT: jmp{{.*}}<bar>
+
+; Check that bar and __wrap_bar retain their original binding.
+; BIND:      Name: bar
+; BIND-NEXT: Value:
+; BIND-NEXT: Size:
+; BIND-NEXT: Binding: Local
+; BIND:      Name: __wrap_bar
+; BIND-NEXT: Value:
+; BIND-NEXT: Size:
+; BIND-NEXT: Binding: Local
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @bar()
+declare void @__real_bar()
+
+define void @foo() {
+  call void @bar()
+  call void @__real_bar()
+  ret void
+}
diff --git a/test/ELF/many-alloc-sections.s b/test/ELF/many-alloc-sections.s
new file mode 100644 (file)
index 0000000..648ab82
--- /dev/null
@@ -0,0 +1,107 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o
+// RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } }" > %t.script
+// FIXME: threads are disable because the test is too slow with them (PR32942).
+// RUN: ld.lld -T %t.script %t.o -o %t --no-threads
+// RUN: llvm-readobj -t %t | FileCheck %s
+
+// Test that _start is in the correct section.
+// CHECK:      Name: _start
+// CHECK-NEXT: Value: 0x120
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: dm
+
+.macro gen_sections4 x
+        .section a\x,"a"
+        .section b\x,"a"
+        .section c\x,"a"
+        .section d\x,"a"
+.endm
+
+.macro gen_sections8 x
+        gen_sections4 a\x
+        gen_sections4 b\x
+.endm
+
+.macro gen_sections16 x
+        gen_sections8 a\x
+        gen_sections8 b\x
+.endm
+
+.macro gen_sections32 x
+        gen_sections16 a\x
+        gen_sections16 b\x
+.endm
+
+.macro gen_sections64 x
+        gen_sections32 a\x
+        gen_sections32 b\x
+.endm
+
+.macro gen_sections128 x
+        gen_sections64 a\x
+        gen_sections64 b\x
+.endm
+
+.macro gen_sections256 x
+        gen_sections128 a\x
+        gen_sections128 b\x
+.endm
+
+.macro gen_sections512 x
+        gen_sections256 a\x
+        gen_sections256 b\x
+.endm
+
+.macro gen_sections1024 x
+        gen_sections512 a\x
+        gen_sections512 b\x
+.endm
+
+.macro gen_sections2048 x
+        gen_sections1024 a\x
+        gen_sections1024 b\x
+.endm
+
+.macro gen_sections4096 x
+        gen_sections2048 a\x
+        gen_sections2048 b\x
+.endm
+
+.macro gen_sections8192 x
+        gen_sections4096 a\x
+        gen_sections4096 b\x
+.endm
+
+.macro gen_sections16384 x
+        gen_sections8192 a\x
+        gen_sections8192 b\x
+.endm
+
+.macro gen_sections32768 x
+        gen_sections16384 a\x
+        gen_sections16384 b\x
+.endm
+
+        .bss
+        .section bar
+
+gen_sections32768 a
+gen_sections16384 b
+gen_sections8192 c
+gen_sections4096 d
+gen_sections2048 e
+gen_sections1024 f
+gen_sections512 g
+gen_sections128 h
+gen_sections64 i
+gen_sections32 j
+gen_sections16 k
+gen_sections8 l
+gen_sections4 m
+
+.global _start
+_start:
diff --git a/test/ELF/many-sections.s b/test/ELF/many-sections.s
new file mode 100644 (file)
index 0000000..7ef0f7c
--- /dev/null
@@ -0,0 +1,124 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t
+// RUN: llvm-readobj -t %t | FileCheck  %s
+
+// Verify that the symbol _start is in a section with an index >= SHN_LORESERVE.
+// CHECK:      Name: _start
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: dm (0xFF00)
+
+
+// FIXME: threads are disable because the test is too slow with them (PR32942).
+// RUN: ld.lld %t -o %t2 --no-threads
+// RUN: llvm-readobj -t %t2 | FileCheck --check-prefix=LINKED %s
+
+// Test also with a linker script.
+// RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } }" > %t.script
+// FIXME: threads are disable because the test is too slow with them (PR32942).
+// RUN: ld.lld -T %t.script %t -o %t2 --no-threads
+// RUN: llvm-readobj -t %t2 | FileCheck --check-prefix=LINKED %s
+
+// Test that _start is in the correct section.
+// LINKED:      Name: _start
+// LINKED-NEXT: Value: 0x0
+// LINKED-NEXT: Size: 0
+// LINKED-NEXT: Binding: Global
+// LINKED-NEXT: Type: None
+// LINKED-NEXT: Other: 0
+// LINKED-NEXT: Section: dm
+
+.macro gen_sections4 x
+        .section a\x
+        .section b\x
+        .section c\x
+        .section d\x
+.endm
+
+.macro gen_sections8 x
+        gen_sections4 a\x
+        gen_sections4 b\x
+.endm
+
+.macro gen_sections16 x
+        gen_sections8 a\x
+        gen_sections8 b\x
+.endm
+
+.macro gen_sections32 x
+        gen_sections16 a\x
+        gen_sections16 b\x
+.endm
+
+.macro gen_sections64 x
+        gen_sections32 a\x
+        gen_sections32 b\x
+.endm
+
+.macro gen_sections128 x
+        gen_sections64 a\x
+        gen_sections64 b\x
+.endm
+
+.macro gen_sections256 x
+        gen_sections128 a\x
+        gen_sections128 b\x
+.endm
+
+.macro gen_sections512 x
+        gen_sections256 a\x
+        gen_sections256 b\x
+.endm
+
+.macro gen_sections1024 x
+        gen_sections512 a\x
+        gen_sections512 b\x
+.endm
+
+.macro gen_sections2048 x
+        gen_sections1024 a\x
+        gen_sections1024 b\x
+.endm
+
+.macro gen_sections4096 x
+        gen_sections2048 a\x
+        gen_sections2048 b\x
+.endm
+
+.macro gen_sections8192 x
+        gen_sections4096 a\x
+        gen_sections4096 b\x
+.endm
+
+.macro gen_sections16384 x
+        gen_sections8192 a\x
+        gen_sections8192 b\x
+.endm
+
+.macro gen_sections32768 x
+        gen_sections16384 a\x
+        gen_sections16384 b\x
+.endm
+
+        .bss
+        .section bar
+
+gen_sections32768 a
+gen_sections16384 b
+gen_sections8192 c
+gen_sections4096 d
+gen_sections2048 e
+gen_sections1024 f
+gen_sections512 g
+gen_sections128 h
+gen_sections64 i
+gen_sections32 j
+gen_sections16 k
+gen_sections8 l
+gen_sections4 m
+
+.global _start
+_start:
diff --git a/test/ELF/map-file.s b/test/ELF/map-file.s
new file mode 100644 (file)
index 0000000..9dbbda0
--- /dev/null
@@ -0,0 +1,59 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file2.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file3.s -o %t3.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file4.s -o %t4.o
+// RUN: rm -f %t4.a
+// RUN: llvm-ar rc %t4.a %t4.o
+// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -M | FileCheck -strict-whitespace %s
+// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -print-map | FileCheck -strict-whitespace %s
+// RUN: ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -Map=%t.map
+// RUN: FileCheck -strict-whitespace %s < %t.map
+
+.global _start
+_start:
+        call baz
+.global _Z1fi
+_Z1fi:
+.cfi_startproc
+.cfi_endproc
+nop
+.weak bar
+bar:
+.long bar - .
+.long zed - .
+local:
+.comm   common,4,16
+
+// CHECK:      Address          Size             Align Out     In      Symbol
+// CHECK-NEXT: 0000000000200158 0000000000000030     8 .eh_frame
+// CHECK-NEXT: 0000000000200158 0000000000000030     8         <internal>:(.eh_frame)
+// CHECK-NEXT: 0000000000201000 0000000000000015     4 .text
+// CHECK-NEXT: 0000000000201000 000000000000000e     4         {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text)
+// CHECK-NEXT: 0000000000201000 0000000000000000     0                 _start
+// CHECK-NEXT: 0000000000201005 0000000000000000     0                 f(int)
+// CHECK-NEXT: 000000000020100e 0000000000000000     0                 local
+// CHECK-NEXT: 0000000000201010 0000000000000002     4         {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text)
+// CHECK-NEXT: 0000000000201010 0000000000000000     0                 foo
+// CHECK-NEXT: 0000000000201011 0000000000000000     0                 bar
+// CHECK-NEXT: 0000000000201012 0000000000000000     1         {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text.zed)
+// CHECK-NEXT: 0000000000201012 0000000000000000     0                 zed
+// CHECK-NEXT: 0000000000201014 0000000000000000     4         {{.*}}{{/|\\}}map-file.s.tmp3.o:(.text)
+// CHECK-NEXT: 0000000000201014 0000000000000000     0                 bah
+// CHECK-NEXT: 0000000000201014 0000000000000001     4         {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text)
+// CHECK-NEXT: 0000000000201014 0000000000000000     0                 baz
+// CHECK-NEXT: 0000000000202000 0000000000000004    16 .bss
+// CHECK-NEXT: 0000000000202000 0000000000000004    16         <internal>:(COMMON)
+// CHECK-NEXT: 0000000000000000 0000000000000008     1 .comment
+// CHECK-NEXT: 0000000000000000 0000000000000008     1         <internal>:(.comment)
+// CHECK-NEXT: 0000000000000000 00000000000000f0     8 .symtab
+// CHECK-NEXT: 0000000000000000 00000000000000f0     8         <internal>:(.symtab)
+// CHECK-NEXT: 0000000000000000 0000000000000039     1 .shstrtab
+// CHECK-NEXT: 0000000000000000 0000000000000039     1         <internal>:(.shstrtab)
+// CHECK-NEXT: 0000000000000000 000000000000002f     1 .strtab
+// CHECK-NEXT: 0000000000000000 000000000000002f     1         <internal>:(.strtab)
+
+// RUN: not ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -Map=/ 2>&1 \
+// RUN:  | FileCheck -check-prefix=FAIL %s
+// FAIL: cannot open map file /
diff --git a/test/ELF/map-gc-sections.s b/test/ELF/map-gc-sections.s
new file mode 100644 (file)
index 0000000..717ab81
--- /dev/null
@@ -0,0 +1,9 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -Map=- --gc-sections | FileCheck %s
+
+.section .tbss,"awT",@nobits
+// CHECK-NOT: foo
+.globl foo
+foo:
+.align 8
+.long 0
diff --git a/test/ELF/merge-reloc.s b/test/ELF/merge-reloc.s
new file mode 100644 (file)
index 0000000..934ac3b
--- /dev/null
@@ -0,0 +1,92 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -r -o %t-rel
+# RUN: llvm-readobj -s -section-data %t-rel | FileCheck %s
+
+# When linker generates a relocatable object it should keep "merge"
+# sections as-is: do not merge content, do not join regular and
+# "merge" sections, do not joint "merge" sections with different
+# entry size.
+
+# CHECK:      Section {
+# CHECK:        Index:
+# CHECK:        Name: .rodata
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 12
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 4
+# CHECK-NEXT:   EntrySize: 4
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: 42000000 42000000 42000000
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+# CHECK:      Section {
+# CHECK:        Index:
+# CHECK:        Name: .rodata
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 16
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 8
+# CHECK-NEXT:   EntrySize: 8
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: 42000000 42000000 42000000 42000000
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+# CHECK:      Section {
+# CHECK:        Index:
+# CHECK:        Name: .data
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 16
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: 42000000 42000000 42000000 42000000
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+
+        .section        .rodata.1,"aM",@progbits,4
+        .align  4
+        .global foo
+foo:
+        .long   0x42
+        .long   0x42
+        .long   0x42
+
+        .section        .rodata.2,"aM",@progbits,8
+        .align  8
+        .global bar
+bar:
+        .long   0x42
+        .long   0x42
+        .long   0x42
+        .long   0x42
+
+        .data
+        .global gar
+zed:
+        .long   0x42
+        .long   0x42
+        .long   0x42
+        .long   0x42
diff --git a/test/ELF/merge-section-types.s b/test/ELF/merge-section-types.s
new file mode 100644 (file)
index 0000000..f846282
--- /dev/null
@@ -0,0 +1,20 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+
+// CHECK:      Name: .foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: Size: 16
+
+.section .foo, "aw", @progbits, unique, 1
+.quad 0
+
+.section .foo, "aw", @nobits, unique, 2
+.quad 0
diff --git a/test/ELF/merge-shared-str.s b/test/ELF/merge-shared-str.s
new file mode 100644 (file)
index 0000000..2ab03a4
--- /dev/null
@@ -0,0 +1,28 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared -O3
+// RUN: llvm-readobj -r -s %t.so | FileCheck %s
+
+
+        .section        foo,"aMS",@progbits,1
+        .asciz "bar"
+        .asciz "ar"
+
+        .data
+        .quad foo + 4
+
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x1C9
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/merge-shared.s b/test/ELF/merge-shared.s
new file mode 100644 (file)
index 0000000..4c1d7c0
--- /dev/null
@@ -0,0 +1,26 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s %t.so | FileCheck %s
+
+       .section        foo,"aM",@progbits,4
+        .long 42
+        .long 42
+
+        .data
+        .quad foo + 6
+
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x1CA
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/merge-string-align.s b/test/ELF/merge-string-align.s
new file mode 100644 (file)
index 0000000..bcad6ee
--- /dev/null
@@ -0,0 +1,56 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+        .section        .rodata.foo,"aMS",@progbits,1
+        .align  16
+        .asciz "foo"
+
+        .section        .rodata.foo2,"aMS",@progbits,1
+        .align  16
+        .asciz "foo"
+
+        .section        .rodata.bar,"aMS",@progbits,1
+        .align  16
+        .asciz "bar"
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 20
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000:  666F6F00 00000000 00000000 00000000  |foo.............|
+// CHECK-NEXT:   0010:  62617200                             |bar.|
+// CHECK-NEXT: )
+
+        .section        .rodata2,"aMS",@progbits,1
+        .asciz "foo"
+
+// CHECK:      Name: .rodata2
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000:  666F6F00 |foo.|
+// CHECK-NEXT: )
diff --git a/test/ELF/merge-string-empty.s b/test/ELF/merge-string-empty.s
new file mode 100644 (file)
index 0000000..0b82ce7
--- /dev/null
@@ -0,0 +1,12 @@
+// Ensure that a mergeable string with size 0 does not cause any issue.
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+
+.globl _start, s
+.section .rodata.str1.1,"aMS",@progbits,1
+s:
+.text
+_start:
+       .quad s
diff --git a/test/ELF/merge-string-error.s b/test/ELF/merge-string-error.s
new file mode 100644 (file)
index 0000000..78895ce
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+        .section       .rodata.str1.1,"aMS",@progbits,1
+       .asciz  "abc"
+
+        .data
+        .long .rodata.str1.1 + 4
+
+// CHECK: merge-string-error.s.tmp.o:(.rodata.str1.1): entry is past the end of the section
diff --git a/test/ELF/merge-string-no-null.s b/test/ELF/merge-string-no-null.s
new file mode 100644 (file)
index 0000000..fd3f507
--- /dev/null
@@ -0,0 +1,8 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+       .section        .rodata.str1.1,"aMS",@progbits,1
+       .ascii  "abc"
+
+// CHECK: string is not null terminated
diff --git a/test/ELF/merge-string.s b/test/ELF/merge-string.s
new file mode 100644 (file)
index 0000000..13c89f0
--- /dev/null
@@ -0,0 +1,105 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -O2 %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s
+// RUN: ld.lld -O1 %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck --check-prefix=NOTAIL %s
+// RUN: ld.lld -O0 %t.o -o %t.so -shared
+// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck --check-prefix=NOMERGE %s
+
+        .section       .rodata1,"aMS",@progbits,1
+       .asciz  "abc"
+foo:
+       .ascii  "a"
+bar:
+        .asciz  "bc"
+        .asciz  "bc"
+
+        .section        .rodata2,"aMS",@progbits,2
+        .align  2
+zed:
+        .short  20
+        .short  0
+
+// CHECK:      Name:    .rodata1
+// CHECK-NEXT: Type:    SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:         0x1C8
+// CHECK-NEXT: Offset:  0x1C8
+// CHECK-NEXT: Size:    4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 61626300                             |abc.|
+// CHECK-NEXT: )
+
+// NOTAIL:      Name:    .rodata1
+// NOTAIL-NEXT: Type:    SHT_PROGBITS
+// NOTAIL-NEXT: Flags [
+// NOTAIL-NEXT:   SHF_ALLOC
+// NOTAIL-NEXT:   SHF_MERGE
+// NOTAIL-NEXT:   SHF_STRINGS
+// NOTAIL-NEXT: ]
+// NOTAIL-NEXT: Address:         0x1C8
+// NOTAIL-NEXT: Offset:  0x1C8
+// NOTAIL-NEXT: Size:    7
+// NOTAIL-NEXT: Link: 0
+// NOTAIL-NEXT: Info: 0
+// NOTAIL-NEXT: AddressAlignment: 1
+// NOTAIL-NEXT: EntrySize: 0
+// NOTAIL-NEXT: SectionData (
+// NOTAIL-NEXT:   0000: 61626300 626300                     |abc.bc.|
+// NOTAIL-NEXT: )
+
+// NOMERGE:      Name:    .rodata1
+// NOMERGE-NEXT: Type:    SHT_PROGBITS
+// NOMERGE-NEXT: Flags [
+// NOMERGE-NEXT:   SHF_ALLOC
+// NOMERGE-NEXT:   SHF_MERGE
+// NOMERGE-NEXT:   SHF_STRINGS
+// NOMERGE-NEXT: ]
+// NOMERGE-NEXT: Address:         0x1C8
+// NOMERGE-NEXT: Offset:  0x1C8
+// NOMERGE-NEXT: Size:    11
+// NOMERGE-NEXT: Link: 0
+// NOMERGE-NEXT: Info: 0
+// NOMERGE-NEXT: AddressAlignment: 1
+// NOMERGE-NEXT: EntrySize: 1
+// NOMERGE-NEXT: SectionData (
+// NOMERGE-NEXT:   0000: 61626300 61626300 626300 |abc.abc.bc.|
+// NOMERGE-NEXT: )
+
+// CHECK:      Name: .rodata2
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1CC
+// CHECK-NEXT: Offset: 0x1CC
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 2
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 14000000                             |....|
+// CHECK-NEXT: )
+
+
+// CHECK:      Name:    bar
+// CHECK-NEXT: Value:   0x1C9
+
+// CHECK:      Name:    foo
+// CHECK-NEXT: Value:   0x1C8
+
+// CHECK:      Name: zed
+// CHECK-NEXT: Value: 0x1CC
+// CHECK-NEXT: Size: 0
diff --git a/test/ELF/merge-sym.s b/test/ELF/merge-sym.s
new file mode 100644 (file)
index 0000000..4a4e982
--- /dev/null
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -t -s %t.so | FileCheck %s
+
+        .section        .rodata.cst4,"aM",@progbits,4
+        .short 0
+foo:
+        .short 42
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x1CA
diff --git a/test/ELF/merge.s b/test/ELF/merge.s
new file mode 100644 (file)
index 0000000..fba4134
--- /dev/null
@@ -0,0 +1,111 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/merge.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t
+// RUN: llvm-readobj -s -section-data -t %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+        .section        .mysec,"aM",@progbits,4
+        .align  4
+        .global foo
+        .hidden foo
+        .long   0x10
+foo:
+        .long   0x42
+bar:
+        .long   0x42
+zed:
+        .long   0x42
+
+// CHECK:      Name: .mysec
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_MERGE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x200120
+// CHECK-NEXT:    Offset: 0x120
+// CHECK-NEXT:    Size: 8
+// CHECK-NEXT:    Link: 0
+// CHECK-NEXT:    Info: 0
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize: 0
+// CHECK-NEXT:    SectionData (
+// CHECK-NEXT:      0000: 10000000 42000000
+// CHECK-NEXT:    )
+
+
+// Address of the constant 0x10 = 0x200120 = 2097440
+// Address of the constant 0x42 = 0x200124 = 2097444
+
+// CHECK:      Symbols [
+
+// CHECK:        Name: bar
+// CHECK-NEXT:   Value: 0x200124
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Loca
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .mysec
+
+// CHECK:        Name: zed
+// CHECK-NEXT:   Value: 0x200124
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .mysec
+
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value: 0x200124
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [ (0x2)
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .mysec
+
+ // CHECK: ]
+
+        .text
+        .globl  _start
+_start:
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+
+        movl .mysec, %eax
+// addr(0x10) = 2097440
+// DISASM-NEXT:   movl    2097440, %eax
+
+        movl .mysec+7, %eax
+// addr(0x42) + 3 = 2097444 + 3 = 2097447
+// DISASM-NEXT:   movl    2097447, %eax
+
+        movl .mysec+8, %eax
+// addr(0x42) = 2097444
+// DISASM-NEXT:   movl    2097444, %eax
+
+        movl bar+7, %eax
+// addr(0x42) + 7 = 2097444 + 7 = 2097451
+// DISASM-NEXT:   movl    2097451, %eax
+
+        movl bar+8, %eax
+// addr(0x42) + 8 = 2097444 + 8 = 2097452
+// DISASM-NEXT:   movl    2097452, %eax
+
+        movl foo, %eax
+// addr(0x42) = 2097444
+// DISASM-NEXT:   movl    2097444, %eax
+
+        movl foo+7, %eax
+// addr(0x42) + 7 =  = 2097444 + 7 = 2097451
+// DISASM-NEXT:   movl    2097451, %eax
+
+        movl foo+8, %eax
+// addr(0x42) + 8 =  = 2097444 + 8 = 2097452
+// DISASM-NEXT:   movl    2097452, %eax
+
+//  From the other file:  movl .mysec, %eax
+// addr(0x42) = 2097444
+// DISASM-NEXT:   movl    2097444, %eax
diff --git a/test/ELF/mips-26-mask.s b/test/ELF/mips-26-mask.s
new file mode 100644 (file)
index 0000000..4cf56cf
--- /dev/null
@@ -0,0 +1,16 @@
+# Check reading/writing implicit addend for R_MIPS_26 relocation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK:      __start:
+# CHECK-NEXT:   20000:       0e 00 80 00     jal     134348800
+
+  .text
+  .global __start
+__start:
+  jal __start+0x8000000
diff --git a/test/ELF/mips-26.s b/test/ELF/mips-26.s
new file mode 100644 (file)
index 0000000..749920b
--- /dev/null
@@ -0,0 +1,95 @@
+# Check R_MIPS_26 relocation handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t2.o -shared -o %t.so
+# RUN: ld.lld %t1.o %t.so -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+# RUN: llvm-readobj -dynamic-table -s -r -mips-plt-got %t.exe \
+# RUN:   | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: bar:
+# CHECK-NEXT:   20000:       0c 00 80 06     jal     131096 <loc>
+# CHECK-NEXT:   20004:       00 00 00 00     nop
+#
+# CHECK:      __start:
+# CHECK-NEXT:   20008:       0c 00 80 00     jal     131072 <bar>
+# CHECK-NEXT:   2000c:       00 00 00 00     nop
+# CHECK-NEXT:   20010:       0c 00 80 10     jal     131136
+#                                                    ^-- 0x20040 gotplt[foo0]
+# CHECK-NEXT:   20014:       00 00 00 00     nop
+#
+# CHECK:      loc:
+# CHECK-NEXT:   20018:       00 00 00 00     nop
+# CHECK-NEXT: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# CHECK-NEXT:   20020:       3c 1c 00 03     lui     $gp, 3
+# CHECK-NEXT:   20024:       8f 99 00 04     lw      $25, 4($gp)
+# CHECK-NEXT:   20028:       27 9c 00 04     addiu   $gp, $gp, 4
+# CHECK-NEXT:   2002c:       03 1c c0 23     subu    $24, $24, $gp
+# CHECK-NEXT:   20030:       03 e0 78 25     move    $15, $ra
+# CHECK-NEXT:   20034:       00 18 c0 82     srl     $24, $24, 2
+# CHECK-NEXT:   20038:       03 20 f8 09     jalr    $25
+# CHECK-NEXT:   2003c:       27 18 ff fe     addiu   $24, $24, -2
+# CHECK-NEXT:   20040:       3c 0f 00 03     lui     $15, 3
+# CHECK-NEXT:   20044:       8d f9 00 0c     lw      $25, 12($15)
+# CHECK-NEXT:   20048:       03 20 00 08     jr      $25
+# CHECK-NEXT:   2004c:       25 f8 00 0c     addiu   $24, $15, 12
+
+# REL:      Name: .plt
+# REL-NEXT: Type: SHT_PROGBITS
+# REL-NEXT: Flags [ (0x6)
+# REL-NEXT:   SHF_ALLOC
+# REL-NEXT:   SHF_EXECINSTR
+# REL-NEXT: ]
+# REL-NEXT: Address: 0x[[PLTADDR:[0-9A-F]+]]
+
+# REL:      Name: .got.plt
+# REL-NEXT: Type: SHT_PROGBITS
+# REL-NEXT: Flags [ (0x3)
+# REL-NEXT:   SHF_ALLOC
+# REL-NEXT:   SHF_WRITE
+# REL-NEXT: ]
+# REL-NEXT: Address: 0x[[GOTPLTADDR:[0-9A-F]+]]
+
+# REL: Relocations [
+# REL-NEXT:   Section (7) .rel.plt {
+# REL-NEXT:     0x[[PLTSLOT:[0-9A-F]+]] R_MIPS_JUMP_SLOT foo0 0x0
+# REL-NEXT:   }
+# REL-NEXT: ]
+
+# REL: 0x70000032  MIPS_PLTGOT  0x[[GOTPLTADDR]]
+
+# REL:      Primary GOT {
+# REL:        Local entries [
+# REL-NEXT:   ]
+# REL-NEXT:   Global entries [
+# REL-NEXT:   ]
+# REL:      PLT GOT {
+# REL:        Entries [
+# REL-NEXT:     Entry {
+# REL-NEXT:       Address: 0x[[PLTSLOT]]
+# REL-NEXT:       Initial: 0x[[PLTADDR]]
+# REL-NEXT:       Value: 0x0
+# REL-NEXT:       Type: Function
+# REL-NEXT:       Section: Undefined
+# REL-NEXT:       Name: foo0
+# REL-NEXT:     }
+# REL-NEXT:   ]
+
+  .text
+  .globl bar
+bar:
+  jal loc         # R_MIPS_26 against .text + offset
+
+  .globl __start
+__start:
+  jal bar         # R_MIPS_26 against global 'bar' from object file
+  jal foo0        # R_MIPS_26 against 'foo0' from DSO
+
+loc:
+  nop
diff --git a/test/ELF/mips-32.s b/test/ELF/mips-32.s
new file mode 100644 (file)
index 0000000..ef97afc
--- /dev/null
@@ -0,0 +1,79 @@
+# Check R_MIPS_32 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: ld.lld -shared %t-be.o -o %t-be.so
+# RUN: llvm-objdump -t -s %t-be.so \
+# RUN:   | FileCheck -check-prefix=SYM -check-prefix=BE %s
+# RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-be.so \
+# RUN:   | FileCheck -check-prefix=REL %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: ld.lld -shared %t-el.o -o %t-el.so
+# RUN: llvm-objdump -t -s %t-el.so \
+# RUN:   | FileCheck -check-prefix=SYM -check-prefix=EL %s
+# RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-el.so \
+# RUN:   | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+  .globl  __start
+__start:
+  nop
+
+  .data
+  .type  v1,@object
+  .size  v1,4
+v1:
+  .word 0
+
+  .globl v2
+  .type  v2,@object
+  .size  v2,8
+v2:
+  .word v2+4 # R_MIPS_32 target v2 addend 4
+  .word v1   # R_MIPS_32 target v1 addend 0
+
+# BE: Contents of section .data:
+# BE-NEXT: 20000 00000000 00000004 00020000
+#                         ^-- v2+4 ^-- v1
+
+# EL: Contents of section .data:
+# EL-NEXT: 20000 00000000 04000000 00000200
+#                         ^-- v2+4 ^-- v1
+
+# SYM: SYMBOL TABLE:
+# SYM: 00020000 l       .data           00000004 v1
+# SYM: 00020004 g       .data           00000008 v2
+
+# REL:      Relocations [
+# REL-NEXT:   Section (7) .rel.dyn {
+# REL-NEXT:     0x20008 R_MIPS_REL32 - 0x0
+# REL-NEXT:     0x20004 R_MIPS_REL32 v2 0x0
+# REL-NEXT:   }
+# REL-NEXT: ]
+
+# REL:   DynamicSection [
+# REL:     Tag        Type                 Name/Value
+# REL:     0x00000012 RELSZ                16 (bytes)
+# REL:     0x00000013 RELENT               8 (bytes)
+# REL-NOT: 0x6FFFFFFA RELCOUNT
+
+# REL:      Primary GOT {
+# REL-NEXT:   Canonical gp value:
+# REL-NEXT:   Reserved entries [
+# REL:        ]
+# REL-NEXT:   Local entries [
+# REL-NEXT:   ]
+# REL-NEXT:   Global entries [
+# REL-NEXT:     Entry {
+# REL-NEXT:       Address:
+# REL-NEXT:       Access:
+# REL-NEXT:       Initial: 0x20004
+# REL-NEXT:       Value: 0x20004
+# REL-NEXT:       Type: Object
+# REL-NEXT:       Section: .data
+# REL-NEXT:       Name: v2
+# REL-NEXT:     }
+# REL-NEXT:   ]
+# REL-NEXT:   Number of TLS and multi-GOT entries: 0
+# REL-NEXT: }
diff --git a/test/ELF/mips-64-disp.s b/test/ELF/mips-64-disp.s
new file mode 100644 (file)
index 0000000..29b62dc
--- /dev/null
@@ -0,0 +1,88 @@
+# Check R_MIPS_GOT_DISP relocations against various kind of symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %p/Inputs/mips-pic.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.exe.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.exe.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      __start:
+# CHECK-NEXT:    20000:   24 42 80 40   addiu   $2, $2, -32704
+# CHECK-NEXT:    20004:   24 42 80 20   addiu   $2, $2, -32736
+# CHECK-NEXT:    20008:   24 42 80 28   addiu   $2, $2, -32728
+# CHECK-NEXT:    2000c:   24 42 80 30   addiu   $2, $2, -32720
+# CHECK-NEXT:    20010:   24 42 80 38   addiu   $2, $2, -32712
+
+# CHECK: 0000000000020014     .text   00000000 foo
+# CHECK: 0000000000020000     .text   00000000 __start
+# CHECK: 0000000000000000 g F *UND*   00000000 foo1a
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+# GOT-NEXT: Primary GOT {
+# GOT-NEXT:   Canonical gp value:
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x8000000000000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x20014
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32728
+# GOT-NEXT:       Initial: 0x20004
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32720
+# GOT-NEXT:       Initial: 0x20008
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32712
+# GOT-NEXT:       Initial: 0x2000C
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32704
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: Function
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: foo1a
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .global  __start
+__start:
+  addiu   $v0,$v0,%got_disp(foo1a)            # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(foo)              # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+4)          # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+8)          # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(.text+12)         # R_MIPS_GOT_DISP
+
+foo:
+  nop
diff --git a/test/ELF/mips-64-got.s b/test/ELF/mips-64-got.s
new file mode 100644 (file)
index 0000000..f2b4d5b
--- /dev/null
@@ -0,0 +1,91 @@
+# Check MIPS N64 ABI GOT relocations
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %p/Inputs/mips-pic.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.exe.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.exe.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      __start:
+
+# CHECK-NEXT:    20000:   df 82 80 20   ld      $2, -32736($gp)
+# CHECK-NEXT:    20004:   64 42 00 18   daddiu  $2,  $2, 24
+# CHECK-NEXT:    20008:   24 42 80 40   addiu   $2,  $2, -32704
+# CHECK-NEXT:    2000c:   24 42 80 30   addiu   $2,  $2, -32720
+# CHECK-NEXT:    20010:   24 42 80 38   addiu   $2,  $2, -32712
+
+# CHECK: 0000000000020018   .text   00000000 foo
+# CHECK: 0000000000020000   .text   00000000 __start
+# CHECK: 0000000000020014   .text   00000000 bar
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+# GOT-NEXT: Primary GOT {
+# GOT-NEXT:   Canonical gp value:
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x8000000000000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x20000
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32728
+# GOT-NEXT:       Initial: 0x30000
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32720
+# GOT-NEXT:       Initial: 0x20014
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32712
+# GOT-NEXT:       Initial: 0x20018
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32704
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: Function
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: foo1a
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .global  __start, bar
+__start:
+  ld      $v0,%got_page(foo)($gp)             # R_MIPS_GOT_PAGE
+  daddiu  $v0,$v0,%got_ofst(foo)              # R_MIPS_GOT_OFST
+  addiu   $v0,$v0,%got_disp(foo1a)            # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(bar)              # R_MIPS_GOT_DISP
+  addiu   $v0,$v0,%got_disp(foo)              # R_MIPS_GOT_DISP
+
+bar:
+  nop
+foo:
+  nop
diff --git a/test/ELF/mips-64-gprel-so.s b/test/ELF/mips-64-gprel-so.s
new file mode 100644 (file)
index 0000000..a390ec0
--- /dev/null
@@ -0,0 +1,23 @@
+# Check setup of GP relative offsets in a function's prologue.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: foo:
+# CHECK-NEXT:    10000:    3c 1c 00 01    lui     $gp, 1
+# CHECK-NEXT:    10004:    03 99 e0 2d    daddu   $gp, $gp, $25
+# CHECK-NEXT:    10008:    67 9c 7f f0    daddiu  $gp, $gp, 32752
+
+# CHECK: 0000000000027ff0   *ABS*   00000000 .hidden _gp
+# CHECK: 0000000000010000   .text   00000000 foo
+
+  .text
+  .global foo
+foo:
+  lui     $gp,%hi(%neg(%gp_rel(foo)))
+  daddu   $gp,$gp,$t9
+  daddiu  $gp,$gp,%lo(%neg(%gp_rel(foo)))
diff --git a/test/ELF/mips-64-rels.s b/test/ELF/mips-64-rels.s
new file mode 100644 (file)
index 0000000..93d893a
--- /dev/null
@@ -0,0 +1,46 @@
+# Check handling multiple MIPS N64 ABI relocations packed
+# into the single relocation record.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# CHECK:      __start:
+# CHECK-NEXT:    20000:   3c 1c 00 01   lui     $gp, 1
+#                                                    ^-- 0x20000 - 0x37ff0
+#                                                    ^-- 0 - 0xfffffffffffe8010
+#                                                    ^-- %hi(0x17ff0)
+# CHECK:      loc:
+# CHECK-NEXT:    20004:   67 9c 7f f0   daddiu  $gp, $gp, 32752
+#                                                    ^-- 0x20000 - 0x37ff0
+#                                                    ^-- 0 - 0xfffffffffffe8010
+#                                                    ^-- %lo(0x17ff0)
+
+# CHECK:      Contents of section .rodata:
+# CHECK-NEXT:  10158 ffffffff fffe8014
+#                    ^-- 0x20004 - 0x37ff0 = 0xfffffffffffe8014
+
+# CHECK: 0000000000020004   .text   00000000 loc
+# CHECK: 0000000000037ff0   *ABS*   00000000 .hidden _gp
+# CHECK: 0000000000020000   .text   00000000 __start
+
+# REL:      Relocations [
+# REL-NEXT: ]
+
+  .text
+  .global  __start
+__start:
+  lui     $gp,%hi(%neg(%gp_rel(__start)))     # R_MIPS_GPREL16
+                                              # R_MIPS_SUB
+                                              # R_MIPS_HI16
+loc:
+  daddiu  $gp,$gp,%lo(%neg(%gp_rel(__start))) # R_MIPS_GPREL16
+                                              # R_MIPS_SUB
+                                              # R_MIPS_LO16
+
+  .section  .rodata,"a",@progbits
+  .gpdword(loc)                               # R_MIPS_GPREL32
+                                              # R_MIPS_64
diff --git a/test/ELF/mips-64.s b/test/ELF/mips-64.s
new file mode 100644 (file)
index 0000000..dd8a58d
--- /dev/null
@@ -0,0 +1,63 @@
+# Check R_MIPS_64 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-objdump -t %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .global  __start
+__start:
+  nop
+
+  .data
+  .type  v1,@object
+  .size  v1,4
+v1:
+  .quad 0
+
+  .globl v2
+  .type  v2,@object
+  .size  v2,8
+v2:
+  .quad v2+8 # R_MIPS_64 target v2 addend 8
+  .quad v1   # R_MIPS_64 target v1 addend 0
+
+
+# SYM: SYMBOL TABLE:
+# SYM: 00020000 l       .data           00000004 v1
+# SYM: 00020008 g       .data           00000008 v2
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rela.dyn {
+# CHECK-NEXT:     0x20010 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x20000
+#                                                             ^-- v1
+# CHECK-NEXT:     0x20008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE v2 0x8
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSection [
+# CHECK:   Tag        Type     Name/Value
+# CHECK:   0x0000000000000008 RELASZ    48 (bytes)
+# CHECK:   0x0000000000000009 RELAENT   24 (bytes)
+
+# CHECK:      Primary GOT {
+# CHECK-NEXT:   Canonical gp value:
+# CHECK-NEXT:   Reserved entries [
+# CHECK:        ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Access:
+# CHECK-NEXT:       Initial: 0x20008
+# CHECK-NEXT:       Value: 0x20008
+# CHECK-NEXT:       Type: Object
+# CHECK-NEXT:       Section: .data
+# CHECK-NEXT:       Name: v2
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
diff --git a/test/ELF/mips-align-err.s b/test/ELF/mips-align-err.s
new file mode 100644 (file)
index 0000000..0c71ffb
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: mips
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o \
+# RUN:         -mcpu=mips32r6
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %S/Inputs/mips-align-err.s -o %t2.o
+# RUN: not ld.lld %t.o %t2.o -o %t.exe 2>&1 | FileCheck %s
+# CHECK: {{.*}}:(.text+0x1): improper alignment for relocation R_MIPS_PC16
+
+        .globl  __start
+__start:
+.zero 1
+        beqc      $5, $6, _foo            # R_MIPS_PC16
diff --git a/test/ELF/mips-call-hilo.s b/test/ELF/mips-call-hilo.s
new file mode 100644 (file)
index 0000000..2504612
--- /dev/null
@@ -0,0 +1,62 @@
+# Check R_MIPS_CALL_HI16 / R_MIPS_CALL_LO16 relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d %t.so | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: foo:
+# CHECK-NEXT:    10000:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    10004:       8c 42 80 20     lw      $2, -32736($2)
+# CHECK-NEXT:    10008:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    1000c:       8c 42 80 18     lw      $2, -32744($2)
+# CHECK-NEXT:    10010:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    10014:       8c 42 80 1c     lw      $2, -32740($2)
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+
+# GOT:      Primary GOT {
+# GOT-NEXT:   Canonical gp value: 0x27FF0
+# GOT:        Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20008
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x10018
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x2000C
+# GOT-NEXT:       Access: -32740
+# GOT-NEXT:       Initial: 0x1001C
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20010
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: None
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: bar
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .global foo
+foo:
+  lui   $2, %call_hi(bar)
+  lw    $2, %call_lo(bar)($2)
+  lui   $2, %call_hi(loc1)
+  lw    $2, %call_lo(loc1)($2)
+  lui   $2, %call_hi(loc2)
+  lw    $2, %call_lo(loc2)($2)
+loc1:
+  nop
+loc2:
+  nop
diff --git a/test/ELF/mips-call16.s b/test/ELF/mips-call16.s
new file mode 100644 (file)
index 0000000..4a5d0bf
--- /dev/null
@@ -0,0 +1,40 @@
+# Check R_MIPS_CALL16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+# RUN: llvm-readobj -mips-plt-got -symbols %t.exe \
+# RUN:   | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%call16(g1)($gp)
+
+  .globl g1
+  .type  g1,@function
+g1:
+  nop
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:      10000:   8f 88 80 18   lw   $8, -32744
+
+# GOT:      Name: g1
+# GOT-NEXT: Value: 0x[[ADDR:[0-9A-F]+]]
+
+# GOT:      Local entries [
+# GOT-NEXT: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT:   Entry {
+# GOT-NEXT:     Address:
+# GOT-NEXT:     Access: -32744
+# GOT-NEXT:     Initial: 0x[[ADDR]]
+# GOT-NEXT:     Value: 0x[[ADDR]]
+# GOT-NEXT:     Type: Function
+# GOT-NEXT:     Section: .text
+# GOT-NEXT:     Name: g1
+# GOT-NEXT:   }
+# GOT-NEXT: ]
diff --git a/test/ELF/mips-dynamic.s b/test/ELF/mips-dynamic.s
new file mode 100644 (file)
index 0000000..15afb02
--- /dev/null
@@ -0,0 +1,98 @@
+# Check MIPS specific .dynamic section entries.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %p/Inputs/mips-dynamic.s -o %td.o
+# RUN: ld.lld -shared %td.o -o %td.so
+
+# RUN: ld.lld %t.o %td.so -o %t.exe
+# RUN: llvm-readobj -sections -dynamic-table %t.exe \
+# RUN:   | FileCheck -check-prefix=EXE %s
+
+# RUN: ld.lld %t.o --image-base=0x123000 %td.so -o %t.exe
+# RUN: llvm-readobj -sections -dynamic-table %t.exe \
+# RUN:   | FileCheck -check-prefix=IMAGE_BASE %s
+
+# RUN: ld.lld -shared %t.o %td.so -o %t.so
+# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \
+# RUN:   | FileCheck -check-prefix=DSO %s
+
+# REQUIRES: mips
+
+# EXE:      Sections [
+# EXE:          Name: .dynamic
+# EXE-NEXT:     Type: SHT_DYNAMIC
+# EXE-NEXT:     Flags [
+# EXE-NEXT:       SHF_ALLOC
+# EXE-NEXT:     ]
+# EXE:          Name: .rld_map
+# EXE-NEXT:     Type: SHT_PROGBITS
+# EXE-NEXT:     Flags [
+# EXE-NEXT:       SHF_ALLOC
+# EXE-NEXT:       SHF_WRITE
+# EXE-NEXT:     ]
+# EXE-NEXT:     Address: [[RLDMAPADDR:0x[0-9a-f]+]]
+# EXE-NEXT:     Offset:
+# EXE-NEXT:     Size: 4
+# EXE:          Name: .got
+# EXE-NEXT:     Type: SHT_PROGBITS
+# EXE-NEXT:     Flags [ (0x10000003)
+# EXE-NEXT:       SHF_ALLOC
+# EXE-NEXT:       SHF_MIPS_GPREL
+# EXE-NEXT:       SHF_WRITE
+# EXE-NEXT:     ]
+# EXE-NEXT:     Address: [[GOTADDR:0x[0-9a-f]+]]
+# EXE-NEXT:     Offset:
+# EXE-NEXT:     Size: 8
+# EXE:      ]
+# EXE:      DynamicSection [
+# EXE-NEXT:   Tag        Type                 Name/Value
+# EXE-DAG:    0x00000003 PLTGOT               [[GOTADDR]]
+# EXE-DAG:    0x70000001 MIPS_RLD_VERSION     1
+# EXE-DAG:    0x70000005 MIPS_FLAGS           NOTPOT
+# EXE-DAG:    0x70000006 MIPS_BASE_ADDRESS    0x10000
+# EXE-DAG:    0x7000000A MIPS_LOCAL_GOTNO     2
+# EXE-DAG:    0x70000011 MIPS_SYMTABNO        2
+# EXE-DAG:    0x70000013 MIPS_GOTSYM          0x2
+# EXE-DAG:    0x70000016 MIPS_RLD_MAP         [[RLDMAPADDR]]
+# EXE:      ]
+
+# IMAGE_BASE: 0x70000006 MIPS_BASE_ADDRESS    0x123000
+
+# DSO:      Sections [
+# DSO:          Name: .dynamic
+# DSO-NEXT:     Type: SHT_DYNAMIC
+# DSO-NEXT:     Flags [
+# DSO-NEXT:       SHF_ALLOC
+# DSO-NEXT:     ]
+# DSO:          Name: .got
+# DSO-NEXT:     Type: SHT_PROGBITS
+# DSO-NEXT:     Flags [ (0x10000003)
+# DSO-NEXT:       SHF_ALLOC
+# DSO-NEXT:       SHF_MIPS_GPREL
+# DSO-NEXT:       SHF_WRITE
+# DSO-NEXT:     ]
+# DSO-NEXT:     Address: [[GOTADDR:0x[0-9a-f]+]]
+# DSO-NEXT:     Offset:
+# DSO-NEXT:     Size: 8
+# DSO:      ]
+# DSO:      DynamicSymbols [
+# DSO:          Name: @
+# DSO:          Name: __start@
+# DSO:          Name: _foo@
+# DSO:      ]
+# DSO:      DynamicSection [
+# DSO-NEXT:   Tag        Type                 Name/Value
+# DSO-DAG:    0x00000003 PLTGOT               [[GOTADDR]]
+# DSO-DAG:    0x70000001 MIPS_RLD_VERSION     1
+# DSO-DAG:    0x70000005 MIPS_FLAGS           NOTPOT
+# DSO-DAG:    0x70000006 MIPS_BASE_ADDRESS    0x0
+# DSO-DAG:    0x7000000A MIPS_LOCAL_GOTNO     2
+# DSO-DAG:    0x70000011 MIPS_SYMTABNO        3
+# DSO-DAG:    0x70000013 MIPS_GOTSYM          0x3
+# DSO:      ]
+
+  .text
+  .globl  __start,_foo
+  .type _foo,@function
+__start:
+  nop
diff --git a/test/ELF/mips-dynsym-sort.s b/test/ELF/mips-dynsym-sort.s
new file mode 100644 (file)
index 0000000..7d4559c
--- /dev/null
@@ -0,0 +1,43 @@
+# Check the order of dynamic symbols for the MIPS target.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: ld.lld -shared %t-be.o -o %t-be.so
+# RUN: llvm-readobj -symbols -dyn-symbols %t-be.so | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: ld.lld -shared %t-el.o -o %t-el.so
+# RUN: llvm-readobj -symbols -dyn-symbols %t-el.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .data
+  .globl v1,v2,v3
+v1:
+  .space 4
+v2:
+  .space 4
+v3:
+  .space 4
+
+  .text
+  .globl  __start
+__start:
+  lui $2, %got(v3) # v3 will precede v1 in the GOT
+  lui $2, %got(v1)
+
+# Since all these symbols have global binding,
+# the Symbols section contains them in the original order.
+# CHECK: Symbols [
+# CHECK:     Name: v1
+# CHECK:     Name: v2
+# CHECK:     Name: v3
+# CHECK: ]
+
+# The symbols in the DynamicSymbols section are sorted in compliance with
+# the MIPS rules. v2 comes first as it is not in the GOT.
+# v1 and v3 are sorted according to their order in the GOT.
+# CHECK: DynamicSymbols [
+# CHECK:     Name: v2@
+# CHECK:     Name: v3@
+# CHECK:     Name: v1@
+# CHECK: ]
diff --git a/test/ELF/mips-elf-flags-err.s b/test/ELF/mips-elf-flags-err.s
new file mode 100644 (file)
index 0000000..28d93eb
--- /dev/null
@@ -0,0 +1,86 @@
+# Check MIPS ELF ISA flag calculation if input files have different ISAs.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r2 %s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=R1R2 %s
+
+# Check that lld does not allow to link incompatible ISAs.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips3 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32 -mattr=+fp64 %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=R3R32 %s
+
+# Check that lld does not allow to link incompatible ISAs.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         -mcpu=mips64r6 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         -position-independent -mcpu=octeon %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 \
+# RUN:   | FileCheck -check-prefix=R6OCTEON %s
+
+# Check that lld does not allow to link incompatible floating point ABI.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32 -mattr=+fp64 %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=FPABI %s
+
+# Check that lld take in account EF_MIPS_MACH_XXX ISA flags
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         -position-independent -mcpu=mips64 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         -position-independent -mcpu=octeon %s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=OCTEON %s
+
+# Check that lld does not allow to link incompatible ABIs.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -target-abi n32 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -target-abi o32 %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=N32O32 %s
+
+# Check that lld does not allow to link modules with incompatible NAN flags.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mattr=+nan2008 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=NAN %s
+
+# REQUIRES: mips
+
+  .option pic0
+  .text
+  .global  __start
+__start:
+  nop
+
+# R1R2:      Flags [
+# R1R2-NEXT:   EF_MIPS_ABI_O32
+# R1R2-NEXT:   EF_MIPS_ARCH_32R2
+# R1R2-NEXT:   EF_MIPS_CPIC
+# R1R2-NEXT: ]
+
+# R3R32: target ISA 'mips3' is incompatible with 'mips32': {{.*}}mips-elf-flags-err.s.tmp2.o
+# R6OCTEON: target ISA 'mips64r6' is incompatible with 'octeon': {{.*}}mips-elf-flags-err.s.tmp2.o
+# FPABI: target floating point ABI '-mdouble-float' is incompatible with '-mgp32 -mfp64': {{.*}}mips-elf-flags-err.s.tmp2.o
+
+# OCTEON:      Flags [
+# OCTEON-NEXT:   EF_MIPS_ARCH_64R2
+# OCTEON-NEXT:   EF_MIPS_CPIC
+# OCTEON-NEXT:   EF_MIPS_MACH_OCTEON
+# OCTEON:      ]
+
+# N32O32: error: {{.*}}mips-elf-flags-err.s.tmp2.o is incompatible with {{.*}}mips-elf-flags-err.s.tmp1.o
+
+# NAN: target -mnan=2008 is incompatible with -mnan=legacy: {{.*}}mips-elf-flags-err.s.tmp2.o
diff --git a/test/ELF/mips-elf-flags.s b/test/ELF/mips-elf-flags.s
new file mode 100644 (file)
index 0000000..f8f916c
--- /dev/null
@@ -0,0 +1,172 @@
+# Check generation of MIPS specific ELF header flags.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t-so.o
+# RUN: ld.lld %t-so.o --gc-sections -shared -o %t.so
+# RUN: llvm-readobj -h -mips-abi-flags %t.so | FileCheck -check-prefix=SO %s
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-readobj -h -mips-abi-flags %t.exe | FileCheck -check-prefix=EXE %s
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r2 %s -o %t-r2.o
+# RUN: ld.lld %t-r2.o -o %t-r2.exe
+# RUN: llvm-readobj -h -mips-abi-flags %t-r2.exe \
+# RUN:   | FileCheck -check-prefix=EXE-R2 %s
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r2 %s -o %t-r2.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r5 %S/Inputs/mips-dynamic.s -o %t-r5.o
+# RUN: ld.lld %t-r2.o %t-r5.o -o %t-r5.exe
+# RUN: llvm-readobj -h -mips-abi-flags %t-r5.exe \
+# RUN:   | FileCheck -check-prefix=EXE-R5 %s
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %s -o %t-r6.o
+# RUN: ld.lld %t-r6.o -o %t-r6.exe
+# RUN: llvm-readobj -h -mips-abi-flags %t-r6.exe \
+# RUN:   | FileCheck -check-prefix=EXE-R6 %s
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         -position-independent -mcpu=octeon %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-readobj -h -mips-abi-flags %t.exe \
+# RUN:   | FileCheck -check-prefix=OCTEON %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  nop
+
+# SO:      Flags [
+# SO-NEXT:   EF_MIPS_ABI_O32
+# SO-NEXT:   EF_MIPS_ARCH_32
+# SO-NEXT:   EF_MIPS_CPIC
+# SO-NEXT:   EF_MIPS_PIC
+# SO-NEXT: ]
+# SO:      MIPS ABI Flags {
+# SO-NEXT:   Version: 0
+# SO-NEXT:   ISA: MIPS32
+# SO-NEXT:   ISA Extension: None
+# SO-NEXT:   ASEs [
+# SO-NEXT:   ]
+# SO-NEXT:   FP ABI: Hard float (double precision)
+# SO-NEXT:   GPR size: 32
+# SO-NEXT:   CPR1 size: 32
+# SO-NEXT:   CPR2 size: 0
+# SO-NEXT:   Flags 1 [
+# SO-NEXT:     ODDSPREG
+# SO-NEXT:   ]
+# SO-NEXT:   Flags 2: 0x0
+# SO-NEXT: }
+
+# EXE:      Flags [
+# EXE-NEXT:   EF_MIPS_ABI_O32
+# EXE-NEXT:   EF_MIPS_ARCH_32
+# EXE-NEXT:   EF_MIPS_CPIC
+# EXE-NEXT: ]
+# EXE:      MIPS ABI Flags {
+# EXE-NEXT:   Version: 0
+# EXE-NEXT:   ISA: MIPS32
+# EXE-NEXT:   ISA Extension: None
+# EXE-NEXT:   ASEs [
+# EXE-NEXT:   ]
+# EXE-NEXT:   FP ABI: Hard float (double precision)
+# EXE-NEXT:   GPR size: 32
+# EXE-NEXT:   CPR1 size: 32
+# EXE-NEXT:   CPR2 size: 0
+# EXE-NEXT:   Flags 1 [
+# EXE-NEXT:     ODDSPREG
+# EXE-NEXT:   ]
+# EXE-NEXT:   Flags 2: 0x0
+# EXE-NEXT: }
+
+# EXE-R2:      Flags [
+# EXE-R2-NEXT:   EF_MIPS_ABI_O32
+# EXE-R2-NEXT:   EF_MIPS_ARCH_32R2
+# EXE-R2-NEXT:   EF_MIPS_CPIC
+# EXE-R2-NEXT: ]
+# EXE-R2:      MIPS ABI Flags {
+# EXE-R2-NEXT:   Version: 0
+# EXE-R2-NEXT:   ISA: MIPS32r2
+# EXE-R2-NEXT:   ISA Extension: None
+# EXE-R2-NEXT:   ASEs [
+# EXE-R2-NEXT:   ]
+# EXE-R2-NEXT:   FP ABI: Hard float (double precision)
+# EXE-R2-NEXT:   GPR size: 32
+# EXE-R2-NEXT:   CPR1 size: 32
+# EXE-R2-NEXT:   CPR2 size: 0
+# EXE-R2-NEXT:   Flags 1 [
+# EXE-R2-NEXT:     ODDSPREG
+# EXE-R2-NEXT:   ]
+# EXE-R2-NEXT:   Flags 2: 0x0
+# EXE-R2-NEXT: }
+
+# EXE-R5:      Flags [
+# EXE-R5-NEXT:   EF_MIPS_ABI_O32
+# EXE-R5-NEXT:   EF_MIPS_ARCH_32R2
+# EXE-R5-NEXT:   EF_MIPS_CPIC
+# EXE-R5-NEXT: ]
+# EXE-R5:      MIPS ABI Flags {
+# EXE-R5-NEXT:   Version: 0
+# EXE-R5-NEXT:   ISA: MIPS32r5
+# EXE-R5-NEXT:   ISA Extension: None
+# EXE-R5-NEXT:   ASEs [
+# EXE-R5-NEXT:   ]
+# EXE-R5-NEXT:   FP ABI: Hard float (double precision)
+# EXE-R5-NEXT:   GPR size: 32
+# EXE-R5-NEXT:   CPR1 size: 32
+# EXE-R5-NEXT:   CPR2 size: 0
+# EXE-R5-NEXT:   Flags 1 [
+# EXE-R5-NEXT:     ODDSPREG
+# EXE-R5-NEXT:   ]
+# EXE-R5-NEXT:   Flags 2: 0x0
+# EXE-R5-NEXT: }
+
+# EXE-R6:      Flags [
+# EXE-R6-NEXT:   EF_MIPS_ABI_O32
+# EXE-R6-NEXT:   EF_MIPS_ARCH_32R6
+# EXE-R6-NEXT:   EF_MIPS_CPIC
+# EXE-R6-NEXT:   EF_MIPS_NAN2008
+# EXE-R6-NEXT: ]
+# EXE-R6:      MIPS ABI Flags {
+# EXE-R6-NEXT:   Version: 0
+# EXE-R6-NEXT:   ISA: MIPS32
+# EXE-R6-NEXT:   ISA Extension: None
+# EXE-R6-NEXT:   ASEs [
+# EXE-R6-NEXT:   ]
+# EXE-R6-NEXT:   FP ABI: Hard float (32-bit CPU, 64-bit FPU)
+# EXE-R6-NEXT:   GPR size: 32
+# EXE-R6-NEXT:   CPR1 size: 64
+# EXE-R6-NEXT:   CPR2 size: 0
+# EXE-R6-NEXT:   Flags 1 [
+# EXE-R6-NEXT:     ODDSPREG
+# EXE-R6-NEXT:   ]
+# EXE-R6-NEXT:   Flags 2: 0x0
+# EXE-R6-NEXT: }
+
+# OCTEON:      Flags [
+# OCTEON-NEXT:   EF_MIPS_ARCH_64R2
+# OCTEON-NEXT:   EF_MIPS_CPIC
+# OCTEON-NEXT:   EF_MIPS_MACH_OCTEON
+# OCTEON-NEXT:   EF_MIPS_PIC
+# OCTEON-NEXT: ]
+# OCTEON:      MIPS ABI Flags {
+# OCTEON-NEXT:   Version: 0
+# OCTEON-NEXT:   ISA: MIPS64r2
+# OCTEON-NEXT:   ISA Extension: Cavium Networks Octeon
+# OCTEON-NEXT:   ASEs [
+# OCTEON-NEXT:   ]
+# OCTEON-NEXT:   FP ABI: Hard float (double precision)
+# OCTEON-NEXT:   GPR size: 64
+# OCTEON-NEXT:   CPR1 size: 64
+# OCTEON-NEXT:   CPR2 size: 0
+# OCTEON-NEXT:   Flags 1 [
+# OCTEON-NEXT:     ODDSPREG
+# OCTEON-NEXT:   ]
+# OCTEON-NEXT:   Flags 2: 0x0
+# OCTEON-NEXT: }
diff --git a/test/ELF/mips-gnu-hash.s b/test/ELF/mips-gnu-hash.s
new file mode 100644 (file)
index 0000000..288d540
--- /dev/null
@@ -0,0 +1,15 @@
+# Shouldn't allow the GNU hash style to be selected with the MIPS target.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: not ld.lld -shared -hash-style=gnu %t-be.o -o %t-be.so 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: not ld.lld -shared -hash-style=gnu %t-el.o -o %t-el.so 2>&1 | FileCheck %s
+
+# CHECK: the .gnu.hash section is not compatible with the MIPS target.
+
+# REQUIRES: mips
+
+  .globl  __start
+__start:
+  nop
diff --git a/test/ELF/mips-got-and-copy.s b/test/ELF/mips-got-and-copy.s
new file mode 100644 (file)
index 0000000..4e3ca5f
--- /dev/null
@@ -0,0 +1,57 @@
+# REQUIRES: mips
+
+# If there are two relocations such that the first one requires
+# dynamic COPY relocation, the second one requires GOT entry
+# creation, linker should create both - dynamic relocation
+# and GOT entry.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rel.dyn {
+# CHECK-NEXT:     0x[[DATA0:[0-9A-F]+]] R_MIPS_COPY data0
+# CHECK-NEXT:     0x[[DATA1:[0-9A-F]+]] R_MIPS_COPY data1
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value:
+# CHECK-NEXT:   Reserved entries [
+# CHECK:        ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Access: -32744
+# CHECK-NEXT:       Initial: 0x[[DATA0]]
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Access: -32740
+# CHECK-NEXT:       Initial: 0x[[DATA1]]
+# CHECK-NEXT:       Value: 0x[[DATA1]]
+# CHECK-NEXT:       Type: Object
+# CHECK-NEXT:       Section: .bss
+# CHECK-NEXT:       Name: data1@
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
+
+  .text
+  .global __start
+__start:
+  # Case A: 'got' relocation goes before 'copy' relocation
+  lui    $t0,%hi(data0)         # R_MIPS_HI16 - requires R_MISP_COPY relocation
+  addi   $t0,$t0,%lo(data0)
+  lw     $t0,%got(data0)($gp)   # R_MIPS_GOT16 - requires GOT entry
+
+  # Case B: 'copy' relocation goes before 'got' relocation
+  lw     $t0,%got(data1)($gp)   # R_MIPS_GOT16 - requires GOT entry
+  lui    $t0,%hi(data1)         # R_MIPS_HI16 - requires R_MISP_COPY relocation
+  addi   $t0,$t0,%lo(data1)
diff --git a/test/ELF/mips-got-extsym.s b/test/ELF/mips-got-extsym.s
new file mode 100644 (file)
index 0000000..3af4ba0
--- /dev/null
@@ -0,0 +1,59 @@
+# Check creation of GOT entries for global symbols in case of executable
+# file linking. Symbols defined in DSO should get entries in the global part
+# of the GOT. Symbols defined in the executable itself should get local GOT
+# entries and does not need a row in .dynsym table.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -dt -t -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Symbols [
+# CHECK:        Symbol {
+# CHECK:          Name: _foo
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+
+# CHECK:        Symbol {
+# CHECK:          Name: bar
+# CHECK-NEXT:     Value: 0x20008
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+
+# CHECK:     DynamicSymbols [
+# CHECK-NOT:      Name: bar
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32744
+# CHECK-NEXT:     Initial: 0x20008
+#                          ^-- bar
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Global entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32740
+# CHECK-NEXT:     Initial: 0x0
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:     Name: _foo@
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%got(bar)($gp)
+  lw      $t0,%got(_foo)($gp)
+
+.global bar
+bar:
+  .word 0
diff --git a/test/ELF/mips-got-hilo.s b/test/ELF/mips-got-hilo.s
new file mode 100644 (file)
index 0000000..fa7e752
--- /dev/null
@@ -0,0 +1,64 @@
+# Check R_MIPS_GOT_HI16 / R_MIPS_GOT_LO16 relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d %t.so | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: foo:
+# CHECK-NEXT:    10000:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    10004:       8c 42 80 20     lw      $2, -32736($2)
+# CHECK-NEXT:    10008:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    1000c:       8c 42 80 18     lw      $2, -32744($2)
+# CHECK-NEXT:    10010:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    10014:       8c 42 80 1c     lw      $2, -32740($2)
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+
+# GOT:      Primary GOT {
+# GOT-NEXT:   Canonical gp value:
+# GOT:        Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x20000
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32740
+# GOT-NEXT:       Initial: 0x20004
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: None
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: bar
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .global foo
+foo:
+  lui   $2, %got_hi(bar)
+  lw    $2, %got_lo(bar)($2)
+  lui   $2, %got_hi(loc1)
+  lw    $2, %got_lo(loc1)($2)
+  lui   $2, %got_hi(loc2)
+  lw    $2, %got_lo(loc2)($2)
+
+  .data
+loc1:
+  .word 0
+loc2:
+  .word 0
diff --git a/test/ELF/mips-got-page.s b/test/ELF/mips-got-page.s
new file mode 100644 (file)
index 0000000..e2dc485
--- /dev/null
@@ -0,0 +1,40 @@
+# Check the case when small section (less that 0x10000 bytes) occupies
+# two adjacent 0xffff-bytes pages. We need to create two GOT entries
+# for R_MIPS_GOT_PAGE relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -o %t.o %s
+# RUN: ld.lld --section-start .rodata=0x27FFC -shared -o %t.so %t.o
+# RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:       Name: bar
+# CHECK-NEXT:  Value: 0x28000
+#                     ^ page-address = (0x28000 + 0x8000) & ~0xffff = 0x30000
+
+# CHECK:       Name: foo
+# CHECK-NEXT:  Value: 0x27FFC
+#                     ^ page-address = (0x27ffc + 0x8000) & ~0xffff = 0x20000
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32736
+# CHECK-NEXT:     Initial: 0x20000
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32728
+# CHECK-NEXT:     Initial: 0x30000
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  ld      $v0,%got_page(foo)($gp)
+  ld      $v0,%got_page(bar)($gp)
+
+  .rodata
+foo:
+  .word 0
+bar:
+  .word 0
diff --git a/test/ELF/mips-got-redundant.s b/test/ELF/mips-got-redundant.s
new file mode 100644 (file)
index 0000000..b4c6a2b
--- /dev/null
@@ -0,0 +1,64 @@
+# Check number of redundant entries in the local part of MIPS GOT.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -mips-plt-got %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32744
+# CHECK-NEXT:     Initial: 0x20000
+#                          ^-- loc1
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32740
+# CHECK-NEXT:     Initial: 0x30000
+#                          ^-- loc2, loc3, loc4
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32736
+# CHECK-NEXT:     Initial: 0x40000
+#                          ^-- redundant
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32732
+# CHECK-NEXT:     Initial: 0x30008
+#                          ^-- glb1
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .globl  foo
+foo:
+  lw      $t0, %got(loc1)($gp)
+  addi    $t0, $t0, %lo(loc1)
+  lw      $t0, %got(loc2)($gp)
+  addi    $t0, $t0, %lo(loc2)
+  lw      $t0, %got(loc3)($gp)
+  addi    $t0, $t0, %lo(loc3)
+  lw      $t0, %got(loc4)($gp)
+  addi    $t0, $t0, %lo(loc4)
+  lw      $t0, %got(glb1)($gp)
+  lw      $t0, %got(glb1)($gp)
+
+  .section .data.1,"aw",%progbits
+loc1:
+  .space 0x10000
+loc2:
+  .word 0
+loc3:
+  .word 0
+  .global glb1
+  .hidden glb1
+glb1:
+  .word 0
+
+  .section .data.2,"aw",%progbits
+loc4:
+  .word 0
diff --git a/test/ELF/mips-got-relocs.s b/test/ELF/mips-got-relocs.s
new file mode 100644 (file)
index 0000000..4471bc2
--- /dev/null
@@ -0,0 +1,100 @@
+# Check R_MIPS_GOT16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o
+# RUN: ld.lld %t-be.o -o %t-be.exe
+# RUN: llvm-objdump -section-headers -t %t-be.exe | FileCheck -check-prefix=EXE_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-be.exe | FileCheck -check-prefix=EXE_GOT_BE %s
+# RUN: llvm-objdump -d %t-be.exe | FileCheck -check-prefix=EXE_DIS_BE %s
+# RUN: llvm-readobj -relocations %t-be.exe | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-be.exe | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o
+# RUN: ld.lld %t-el.o -o %t-el.exe
+# RUN: llvm-objdump -section-headers -t %t-el.exe | FileCheck -check-prefix=EXE_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-el.exe | FileCheck -check-prefix=EXE_GOT_EL %s
+# RUN: llvm-objdump -d %t-el.exe | FileCheck -check-prefix=EXE_DIS_EL %s
+# RUN: llvm-readobj -relocations %t-el.exe | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-el.exe | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: ld.lld -shared %t-be.o -o %t-be.so
+# RUN: llvm-objdump -section-headers -t %t-be.so | FileCheck -check-prefix=DSO_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-be.so | FileCheck -check-prefix=DSO_GOT_BE %s
+# RUN: llvm-objdump -d %t-be.so | FileCheck -check-prefix=DSO_DIS_BE %s
+# RUN: llvm-readobj -relocations %t-be.so | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-be.so | FileCheck -check-prefix=SHFLAGS %s
+
+# RUN: ld.lld -shared %t-el.o -o %t-el.so
+# RUN: llvm-objdump -section-headers -t %t-el.so | FileCheck -check-prefix=DSO_SYM %s
+# RUN: llvm-objdump -s -section=.got %t-el.so | FileCheck -check-prefix=DSO_GOT_EL %s
+# RUN: llvm-objdump -d %t-el.so | FileCheck -check-prefix=DSO_DIS_EL %s
+# RUN: llvm-readobj -relocations %t-el.so | FileCheck -check-prefix=NORELOC %s
+# RUN: llvm-readobj -sections %t-el.so | FileCheck -check-prefix=SHFLAGS %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui $2, %got(v1)
+
+  .data
+  .globl v1
+  .type  v1,@object
+  .size  v1,4
+v1:
+  .word 0
+
+# EXE_SYM: Sections:
+# EXE_SYM: .got 0000000c 0000000000030010 DATA
+# EXE_SYM: SYMBOL TABLE:
+# EXE_SYM: 00038000         *ABS*    00000000 .hidden _gp
+#          ^-- .got + GP offset (0x7ff0)
+# EXE_SYM: 00030000 g       .data               00000004 v1
+
+
+# EXE_GOT_BE: Contents of section .got:
+# EXE_GOT_BE:  30010 00000000 80000000 00030000
+#                    ^        ^        ^-- v1 (0x30000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# EXE_GOT_EL: Contents of section .got:
+# EXE_GOT_EL:  30010 00000000 00000080 00000300
+#                    ^        ^        ^-- v1 (0x30000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# v1GotAddr (0x3000c) - _gp (0x37ff4) = -0x7fe8 => 0x8018 = 32792
+# EXE_DIS_BE:  20000:  3c 02 80 18  lui $2, 32792
+# EXE_DIS_EL:  20000:  18 80 02 3c  lui $2, 32792
+
+# DSO_SYM: Sections:
+# DSO_SYM: .got 0000000c 0000000000020010 DATA
+# DSO_SYM: SYMBOL TABLE:
+# DSO_SYM: 00028000         *ABS*    00000000 .hidden _gp
+#          ^-- .got + GP offset (0x7ff0)
+# DSO_SYM: 00020000 g       .data               00000004 v1
+
+# DSO_GOT_BE: Contents of section .got:
+# DSO_GOT_BE:  20010 00000000 80000000 00020000
+#                    ^        ^        ^-- v1 (0x20000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# DSO_GOT_EL: Contents of section .got:
+# DSO_GOT_EL:  20010 00000000 00000080 00000200
+#                    ^        ^        ^-- v1 (0x20000)
+#                    |        +-- Module pointer (0x80000000)
+#                    +-- Lazy resolver (0x0)
+
+# v1GotAddr (0x2000c) - _gp (0x27ff4) = -0x7fe8 => 0x8018 = 32792
+# DSO_DIS_BE:  10000:  3c 02 80 18  lui $2, 32792
+# DSO_DIS_EL:  10000:  18 80 02 3c  lui $2, 32792
+
+# NORELOC:      Relocations [
+# NORELOC-NEXT: ]
+
+# SHFLAGS:      Name: .got
+# SHFLAGS-NEXT: Type: SHT_PROGBITS
+# SHFLAGS-NEXT: Flags [ (0x10000003)
+#                        ^-- SHF_MIPS_GPREL | SHF_ALLOC | SHF_WRITE
diff --git a/test/ELF/mips-got-string.s b/test/ELF/mips-got-string.s
new file mode 100644 (file)
index 0000000..598865c
--- /dev/null
@@ -0,0 +1,28 @@
+# Check R_MIPS_GOT16 relocation against merge section.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -o %t.o %s
+# RUN: ld.lld -shared -o %t.so %t.o
+# RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Symbol {
+# CHECK:        Name: $.str
+# CHECK-NEXT:   Value: 0xF4
+# CHECK:      }
+
+# CHECK:      Local entries [
+# CHECK-NEXT:   Entry {
+# CHECK-NEXT:     Address:
+# CHECK-NEXT:     Access: -32744
+# CHECK-NEXT:     Initial: 0x0
+# CHECK:        }
+# CHECK:      ]
+
+  .text
+  lw     $t9, %got($.str)($gp)
+  addiu  $a0, $t9, %lo($.str)
+
+  .section  .rodata.str,"aMS",@progbits,1
+$.str:
+  .asciz "foo"
diff --git a/test/ELF/mips-got-weak.s b/test/ELF/mips-got-weak.s
new file mode 100644 (file)
index 0000000..e860bb4
--- /dev/null
@@ -0,0 +1,172 @@
+# Check R_MIPS_GOT16 relocation against weak symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t1.so
+# RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t1.so \
+# RUN:   | FileCheck -check-prefix=NOSYM %s
+# RUN: ld.lld %t.o -shared -Bsymbolic -o %t2.so
+# RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t2.so \
+# RUN:   | FileCheck -check-prefix=SYM %s
+
+# REQUIRES: mips
+
+# NOSYM:      Relocations [
+# NOSYM-NEXT: ]
+
+# NOSYM:        Symbol {
+# NOSYM:          Name: foo
+# NOSYM-NEXT:     Value: 0x20000
+# NOSYM-NEXT:     Size: 0
+# NOSYM-NEXT:     Binding: Weak
+# NOSYM-NEXT:     Type: None
+# NOSYM-NEXT:     Other: 0
+# NOSYM-NEXT:     Section: .data
+# NOSYM-NEXT:   }
+# NOSYM-NEXT:   Symbol {
+# NOSYM-NEXT:     Name: bar
+# NOSYM-NEXT:     Value: 0x0
+# NOSYM-NEXT:     Size: 0
+# NOSYM-NEXT:     Binding: Weak
+# NOSYM-NEXT:     Type: None
+# NOSYM-NEXT:     Other: 0
+# NOSYM-NEXT:     Section: Undefined
+# NOSYM-NEXT:   }
+# NOSYM-NEXT:   Symbol {
+# NOSYM-NEXT:     Name: sym
+# NOSYM-NEXT:     Value: 0x20004
+# NOSYM-NEXT:     Size: 0
+# NOSYM-NEXT:     Binding: Global
+# NOSYM-NEXT:     Type: None
+# NOSYM-NEXT:     Other: 0
+# NOSYM-NEXT:     Section: .data
+# NOSYM-NEXT:   }
+# NOSYM-NEXT: ]
+
+# NOSYM:      0x70000011 MIPS_SYMTABNO        4
+# NOSYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO     2
+# NOSYM-NEXT: 0x70000013 MIPS_GOTSYM          0x1
+
+# NOSYM:      Primary GOT {
+# NOSYM-NEXT:   Canonical gp value:
+# NOSYM-NEXT:   Reserved entries [
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address:
+# NOSYM-NEXT:       Access: -32752
+# NOSYM-NEXT:       Initial: 0x0
+# NOSYM-NEXT:       Purpose: Lazy resolver
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address:
+# NOSYM-NEXT:       Access: -32748
+# NOSYM-NEXT:       Initial: 0x80000000
+# NOSYM-NEXT:       Purpose: Module pointer (GNU extension)
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:   ]
+# NOSYM-NEXT:   Local entries [
+# NOSYM-NEXT:   ]
+# NOSYM-NEXT:   Global entries [
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address:
+# NOSYM-NEXT:       Access: -32744
+# NOSYM-NEXT:       Initial: 0x20000
+# NOSYM-NEXT:       Value: 0x20000
+# NOSYM-NEXT:       Type: None
+# NOSYM-NEXT:       Section: .data
+# NOSYM-NEXT:       Name: foo
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address:
+# NOSYM-NEXT:       Access: -32740
+# NOSYM-NEXT:       Initial: 0x0
+# NOSYM-NEXT:       Value: 0x0
+# NOSYM-NEXT:       Type: None
+# NOSYM-NEXT:       Section: Undefined
+# NOSYM-NEXT:       Name: bar
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:     Entry {
+# NOSYM-NEXT:       Address:
+# NOSYM-NEXT:       Access: -32736
+# NOSYM-NEXT:       Initial: 0x20004
+# NOSYM-NEXT:       Value: 0x20004
+# NOSYM-NEXT:       Type: None
+# NOSYM-NEXT:       Section: .data
+# NOSYM-NEXT:       Name: sym
+# NOSYM-NEXT:     }
+# NOSYM-NEXT:   ]
+# NOSYM-NEXT:   Number of TLS and multi-GOT entries: 0
+# NOSYM-NEXT: }
+
+# SYM:      Relocations [
+# SYM-NEXT: ]
+
+# SYM:        Symbol {
+# SYM:          Name: bar
+# SYM-NEXT:     Value: 0x0
+# SYM-NEXT:     Size: 0
+# SYM-NEXT:     Binding: Weak
+# SYM-NEXT:     Type: None
+# SYM-NEXT:     Other: 0
+# SYM-NEXT:     Section: Undefined
+# SYM-NEXT:   }
+# SYM-NEXT: ]
+
+# SYM:      0x70000011 MIPS_SYMTABNO        4
+# SYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO     4
+# SYM-NEXT: 0x70000013 MIPS_GOTSYM          0x3
+
+# SYM:      Primary GOT {
+# SYM-NEXT:   Canonical gp value:
+# SYM-NEXT:   Reserved entries [
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address:
+# SYM-NEXT:       Access: -32752
+# SYM-NEXT:       Initial: 0x0
+# SYM-NEXT:       Purpose: Lazy resolver
+# SYM-NEXT:     }
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address:
+# SYM-NEXT:       Access: -32748
+# SYM-NEXT:       Initial: 0x80000000
+# SYM-NEXT:       Purpose: Module pointer (GNU extension)
+# SYM-NEXT:     }
+# SYM-NEXT:   ]
+# SYM-NEXT:   Local entries [
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address:
+# SYM-NEXT:       Access: -32744
+# SYM-NEXT:       Initial: 0x20000
+# SYM-NEXT:     }
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address:
+# SYM-NEXT:       Access: -32740
+# SYM-NEXT:       Initial: 0x20004
+# SYM-NEXT:     }
+# SYM-NEXT:   ]
+# SYM-NEXT:   Global entries [
+# SYM-NEXT:     Entry {
+# SYM-NEXT:       Address:
+# SYM-NEXT:       Access: -32736
+# SYM-NEXT:       Initial: 0x0
+# SYM-NEXT:       Value: 0x0
+# SYM-NEXT:       Type: None
+# SYM-NEXT:       Section: Undefined
+# SYM-NEXT:       Name: bar
+# SYM-NEXT:     }
+# SYM-NEXT:   ]
+# SYM-NEXT:   Number of TLS and multi-GOT entries: 0
+# SYM-NEXT: }
+
+  .text
+  .global  sym
+  .weak    foo,bar
+func:
+  lw      $t0,%got(foo)($gp)
+  lw      $t0,%got(bar)($gp)
+  lw      $t0,%got(sym)($gp)
+
+  .data
+  .weak foo
+foo:
+  .word 0
+sym:
+  .word 0
diff --git a/test/ELF/mips-got16-relocatable.s b/test/ELF/mips-got16-relocatable.s
new file mode 100644 (file)
index 0000000..bbacfdb
--- /dev/null
@@ -0,0 +1,40 @@
+# Check writing updated addend for R_MIPS_GOT16 relocation,
+# when produce a relocatable output.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -o %t.o %s
+# RUN: ld.lld -r -o %t %t.o %t.o
+# RUN: llvm-objdump -d -r %t | FileCheck -check-prefix=OBJ %s
+# RUN: ld.lld -shared -o %t.so %t
+# RUN: llvm-objdump -d %t.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+# OBJ:      Disassembly of section .text:
+# OBJ-NEXT: .text:
+# OBJ-NEXT:        0:       8f 99 00 00     lw      $25, 0($gp)
+# OBJ-NEXT:                         00000000:  R_MIPS_GOT16 .data
+# OBJ-NEXT:        4:       27 24 00 00     addiu   $4, $25, 0
+# OBJ-NEXT:                         00000004:  R_MIPS_LO16  .data
+# OBJ-NEXT:        8:       ef ef ef ef     <unknown>
+# OBJ-NEXT:        c:       ef ef ef ef     <unknown>
+# OBJ-NEXT:       10:       8f 99 00 00     lw      $25, 0($gp)
+# OBJ-NEXT:                         00000010:  R_MIPS_GOT16 .data
+# OBJ-NEXT:       14:       27 24 00 10     addiu   $4, $25, 16
+# OBJ-NEXT:                         00000014:  R_MIPS_LO16  .data
+
+# SO:      Disassembly of section .text:
+# SO-NEXT: .text:
+# SO-NEXT:    10000:       8f 99 80 18     lw      $25, -32744($gp)
+# SO-NEXT:    10004:       27 24 00 00     addiu   $4, $25, 0
+# SO-NEXT:    10008:       ef ef ef ef     <unknown>
+# SO-NEXT:    1000c:       ef ef ef ef     <unknown>
+# SO-NEXT:    10010:       8f 99 80 18     lw      $25, -32744($gp)
+# SO-NEXT:    10014:       27 24 00 10     addiu   $4, $25, 16
+
+  .text
+  lw     $t9, %got(.data)($gp)
+  addiu  $a0, $t9, %lo(.data)
+
+  .data
+data:
+  .word 0
diff --git a/test/ELF/mips-got16.s b/test/ELF/mips-got16.s
new file mode 100644 (file)
index 0000000..6ad7b2b
--- /dev/null
@@ -0,0 +1,132 @@
+# Check R_MIPS_GOT16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    10000:       8f 88 80 18     lw      $8, -32744($gp)
+# CHECK-NEXT:    10004:       21 08 00 2c     addi    $8, $8, 44
+# CHECK-NEXT:    10008:       8f 88 80 24     lw      $8, -32732($gp)
+# CHECK-NEXT:    1000c:       21 08 90 00     addi    $8, $8, -28672
+# CHECK-NEXT:    10010:       8f 88 80 28     lw      $8, -32728($gp)
+# CHECK-NEXT:    10014:       21 08 90 04     addi    $8, $8, -28668
+# CHECK-NEXT:    10018:       8f 88 80 28     lw      $8, -32728($gp)
+# CHECK-NEXT:    1001c:       21 08 10 04     addi    $8, $8, 4100
+# CHECK-NEXT:    10020:       8f 88 80 30     lw      $8, -32720($gp)
+# CHECK-NEXT:    10024:       21 08 10 08     addi    $8, $8, 4104
+# CHECK-NEXT:    10028:       8f 88 80 34     lw      $8, -32716($gp)
+#
+# CHECK: SYMBOL TABLE:
+# CHECK: 00041008         .data           00000000 .hidden bar
+# CHECK: 00000000         *UND*           00000000 foo
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+
+# GOT:      Primary GOT {
+# GOT-NEXT:   Canonical gp value:
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32748
+# GOT-NEXT:       Initial: 0x80000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x10000
+#                          ^-- (0x1002c + 0x8000) & ~0xffff
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32740
+# GOT-NEXT:       Initial: 0x20000
+#                          ^-- redundant unused entry
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x20000
+#                          ^-- redundant unused entry
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32732
+# GOT-NEXT:       Initial: 0x30000
+#                          ^-- (0x29000 + 0x8000) & ~0xffff
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32728
+# GOT-NEXT:       Initial: 0x40000
+#                          ^-- (0x29000 + 0x10004 + 0x8000) & ~0xffff
+#                          ^-- (0x29000 + 0x18004 + 0x8000) & ~0xffff
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32724
+# GOT-NEXT:       Initial: 0x50000
+#                          ^-- redundant unused entry
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32720
+# GOT-NEXT:       Initial: 0x41008
+#                          ^-- 'bar' address
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address:
+# GOT-NEXT:       Access: -32716
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: None
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: foo@
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%got($LC0)($gp)
+  addi    $t0,$t0,%lo($LC0)
+  lw      $t0,%got($LC1)($gp)
+  addi    $t0,$t0,%lo($LC1)
+  lw      $t0,%got($LC1+0x10004)($gp)
+  addi    $t0,$t0,%lo($LC1+0x10004)
+  lw      $t0,%got($LC1+0x18004)($gp)
+  addi    $t0,$t0,%lo($LC1+0x18004)
+  lw      $t0,%got(bar)($gp)
+  addi    $t0,$t0,%lo(bar)
+  lw      $t0,%got(foo)($gp)
+$LC0:
+  nop
+
+  .data
+  .space 0x9000
+$LC1:
+  .word 0
+  .space 0x18000
+  .word 0
+.global bar
+.hidden bar
+bar:
+  .word 0
diff --git a/test/ELF/mips-gp-disp.s b/test/ELF/mips-gp-disp.s
new file mode 100644 (file)
index 0000000..62a2b10
--- /dev/null
@@ -0,0 +1,37 @@
+# Check that even if _gp_disp symbol is defined in the shared library
+# we use our own value.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o %S/Inputs/mips-gp-disp.so
+# RUN: llvm-readobj -symbols %t.so | FileCheck -check-prefix=INT-SO %s
+# RUN: llvm-readobj -symbols %S/Inputs/mips-gp-disp.so \
+# RUN:   | FileCheck -check-prefix=EXT-SO %s
+# RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -relocations %t.so | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# INT-SO:      Name: _gp_disp
+# INT-SO-NEXT: Value:
+# INT-SO-NEXT: Size:
+# INT-SO-NEXT: Binding: Local
+
+# EXT-SO:      Name: _gp_disp
+# EXT-SO-NEXT: Value: 0x20000
+
+# DIS:      Disassembly of section .text:
+# DIS-NEXT: __start:
+# DIS-NEXT:    10000:  3c 08 00 01  lui   $8, 1
+# DIS-NEXT:    10004:  21 08 7f f0  addi  $8, $8, 32752
+#                                                 ^-- 0x37ff0 & 0xffff
+# DIS: 00027ff0  *ABS*  00000000 .hidden _gp
+
+# REL:      Relocations [
+# REL-NEXT: ]
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(_gp_disp)
+  addi   $t0,$t0,%lo(_gp_disp)
+  lw     $v0,%call16(_foo)($gp)
diff --git a/test/ELF/mips-gp-ext.s b/test/ELF/mips-gp-ext.s
new file mode 100644 (file)
index 0000000..98b9cbc
--- /dev/null
@@ -0,0 +1,69 @@
+# Check that the linker use a value of _gp symbol defined
+# in a linker script to calculate GOT relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          _gp = ABSOLUTE(.) + 0x100; \
+# RUN:          .got  : { *(.got) } }" > %t.rel.script
+# RUN: ld.lld -shared -o %t.rel.so --script %t.rel.script %t.o
+# RUN: llvm-objdump -s -t %t.rel.so | FileCheck --check-prefix=REL %s
+
+# RUN: echo "SECTIONS { \
+# RUN:          .text : { *(.text) } \
+# RUN:          _gp = 0x200; \
+# RUN:          .got  : { *(.got) } }" > %t.abs.script
+# RUN: ld.lld -shared -o %t.abs.so --script %t.abs.script %t.o
+# RUN: llvm-objdump -s -t %t.abs.so | FileCheck --check-prefix=ABS %s
+
+# REQUIRES: mips
+
+# REL:      Contents of section .text:
+# REL-NEXT:  0000 3c080000 2108010c 8f82fffc
+#                 ^-- %hi(_gp_disp)
+#                          ^-- %lo(_gp_disp)
+#                                   ^-- 8 - (0x10c - 0x100)
+#                                       G - (GP - .got)
+
+# REL:      Contents of section .reginfo:
+# REL-NEXT:  0028 10000104 00000000 00000000 00000000
+# REL-NEXT:  0038 00000000 0000010c
+#                          ^-- _gp
+
+# REL:      Contents of section .data:
+# REL-NEXT:  00f0 fffffef4
+#                 ^-- 0-0x10c
+
+# REL: 00000000         .text           00000000 foo
+# REL: 00000000         *ABS*           00000000 .hidden _gp_disp
+# REL: 0000010c         *ABS*           00000000 .hidden _gp
+
+# ABS:      Contents of section .text:
+# ABS-NEXT:  0000 3c080000 21080200 8f82ff08
+#                 ^-- %hi(_gp_disp)
+#                          ^-- %lo(_gp_disp)
+#                                   ^-- 8 - (0x200 - 0x100)
+#                                       G - (GP - .got)
+
+# ABS:      Contents of section .reginfo:
+# ABS-NEXT:  0028 10000104 00000000 00000000 00000000
+# ABS-NEXT:  0038 00000000 00000200
+#                          ^-- _gp
+
+# ABS:      Contents of section .data:
+# ABS-NEXT:  00f0 fffffe00
+#                 ^-- 0-0x200
+
+# ABS: 00000000         .text           00000000 foo
+# ABS: 00000000         *ABS*           00000000 .hidden _gp_disp
+# ABS: 00000200         *ABS*           00000000 .hidden _gp
+
+  .text
+foo:
+  lui    $t0, %hi(_gp_disp)
+  addi   $t0, $t0, %lo(_gp_disp)
+  lw     $v0, %call16(bar)($gp)
+
+  .data
+  .gpword foo
diff --git a/test/ELF/mips-gp-local.s b/test/ELF/mips-gp-local.s
new file mode 100644 (file)
index 0000000..b77dbb8
--- /dev/null
@@ -0,0 +1,20 @@
+# Check handling of relocations against __gnu_local_gp symbol.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -o %t.exe %t.o
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:  3c 08 00 03  lui   $8, 3
+# CHECK-NEXT:    20004:  21 08 7f f0  addi  $8, $8, 32752
+
+# CHECK: 00037ff0  *ABS*  00000000 .hidden _gp
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__gnu_local_gp)
+  addi   $t0,$t0,%lo(__gnu_local_gp)
diff --git a/test/ELF/mips-gp-lowest.s b/test/ELF/mips-gp-lowest.s
new file mode 100644 (file)
index 0000000..32a3e85
--- /dev/null
@@ -0,0 +1,44 @@
+# Check that default _gp value is calculated relative
+# to the GP-relative section with the lowest address.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { \
+# RUN:          .sdata : { *(.sdata) } \
+# RUN:          .got  : { *(.got) } }" > %t.rel.script
+# RUN: ld.lld %t.o --script %t.rel.script -shared -o %t.so
+# RUN: llvm-readobj -s -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .global foo
+foo:
+  lui  $gp, %call16(foo)
+
+  .sdata
+  .word 0
+
+# CHECK:      Section {
+# CHECK:        Name: .sdata
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MIPS_GPREL
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0xE0
+# CHECK:      }
+# CHECK:      Section {
+# CHECK:        Name: .got
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MIPS_GPREL
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0xF0
+# CHECK:      }
+
+# CHECK:      Name: _gp (5)
+# CHECK-NEXT: Value: 0x80D0
+#                    ^-- 0xE0 + 0x7ff0
diff --git a/test/ELF/mips-gprel-sec.s b/test/ELF/mips-gprel-sec.s
new file mode 100644 (file)
index 0000000..dc54f87
--- /dev/null
@@ -0,0 +1,37 @@
+# Check order of gp-relative sections, i.e. sections with SHF_MIPS_GPREL flag.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -s %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  nop
+
+  .sdata
+  .word 0
+
+# CHECK:      Section {
+# CHECK:        Name: .got
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MIPS_GPREL
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x20000
+# CHECK-NEXT:   Offset: 0x20000
+# CHECK:      }
+# CHECK:      Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .sdata
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MIPS_GPREL
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x20008
+# CHECK-NEXT:   Offset: 0x20008
+# CHECK:      }
diff --git a/test/ELF/mips-gprel32-relocs-gp0.s b/test/ELF/mips-gprel32-relocs-gp0.s
new file mode 100644 (file)
index 0000000..4f1962b
--- /dev/null
@@ -0,0 +1,48 @@
+# Check that relocatable object produced by LLD has zero gp0 value.
+# Also check an error message if input object file has non-zero gp0 value
+# and the linker generates a relocatable object.
+# mips-gp0-non-zero.o is a relocatable object produced from the asm code
+# below and linked by GNU bfd linker.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -r -o %t-rel.o %t.o
+# RUN: llvm-readobj -mips-reginfo %t-rel.o | FileCheck --check-prefix=REL %s
+
+# RUN: ld.lld -shared -o %t.so %S/Inputs/mips-gp0-non-zero.o
+# RUN: llvm-readobj -mips-reginfo %t.so | FileCheck --check-prefix=DSO %s
+# RUN: llvm-objdump -s -t %t.so | FileCheck --check-prefix=DUMP %s
+
+# RUN: not ld.lld -r -o %t-rel.o %S/Inputs/mips-gp0-non-zero.o 2>&1 \
+# RUN:   | FileCheck --check-prefix=ERR %s
+
+# REQUIRES: mips
+
+# REL: GP: 0x0
+
+# DSO: GP: 0x27FF0
+
+# DUMP: Contents of section .rodata:
+# DUMP:  00f4 ffff0004 ffff0008
+#             ^ 0x10004 + 0x7ff0 - 0x27ff0
+#                      ^ 0x10008 + 0x7ff0 - 0x27ff0
+
+# DUMP: SYMBOL TABLE:
+# DUMP: 00010008         .text          00000000 bar
+# DUMP: 00010004         .text          00000000 foo
+# DUMP: 00027ff0         *ABS*          00000000 .hidden _gp
+
+# ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value
+
+  .text
+  .global  __start
+__start:
+  lw      $t0,%call16(__start)($gp)
+foo:
+  nop
+bar:
+  nop
+
+  .section .rodata, "a"
+v:
+  .gpword foo
+  .gpword bar
diff --git a/test/ELF/mips-gprel32-relocs.s b/test/ELF/mips-gprel32-relocs.s
new file mode 100644 (file)
index 0000000..1c877b1
--- /dev/null
@@ -0,0 +1,31 @@
+# Check R_MIPS_GPREL32 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o
+# RUN: llvm-objdump -s -section=.rodata -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%call16(__start)($gp)
+foo:
+  nop
+bar:
+  nop
+
+  .section .rodata, "a"
+v1:
+  .gpword foo
+  .gpword bar
+
+# CHECK: Contents of section .rodata:
+# CHECK:  00f4 fffe8014 fffe8018
+#              ^ 0x10004 - 0x27ff0
+#                       ^ 0x10008 - 0x27ff0
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00010008         .text           00000000 bar
+# CHECK: 00010004         .text           00000000 foo
+# CHECK: 00027ff0         *ABS*           00000000 .hidden _gp
diff --git a/test/ELF/mips-higher-highest.s b/test/ELF/mips-higher-highest.s
new file mode 100644 (file)
index 0000000..123b51a
--- /dev/null
@@ -0,0 +1,21 @@
+# Check R_MIPS_HIGHER / R_MIPS_HIGHEST relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .global  __start
+__start:
+  lui     $6, %highest(_foo+0x300047FFF7FF7)
+  daddiu  $6, $6, %higher(_foo+0x300047FFF7FF7)
+  lui     $7, %highest(_foo+0x300047FFF7FF8)
+  ld      $7, %higher (_foo+0x300047FFF7FF8)($7)
+
+# CHECK:      20000:       3c 06 00 03     lui     $6, 3
+# CHECK-NEXT: 20004:       64 c6 00 05     daddiu  $6, $6, 5
+# CHECK-NEXT: 20008:       3c 07 00 03     lui     $7, 3
+# CHECK-NEXT: 2000c:       dc e7 00 05     ld      $7, 5($7)
diff --git a/test/ELF/mips-hilo-gp-disp.s b/test/ELF/mips-hilo-gp-disp.s
new file mode 100644 (file)
index 0000000..62e03c7
--- /dev/null
@@ -0,0 +1,55 @@
+# Check R_MIPS_HI16 / LO16 relocations calculation against _gp_disp.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck -check-prefix=EXE %s
+# RUN: ld.lld %t1.o %t2.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(_gp_disp)
+  addi   $t0,$t0,%lo(_gp_disp)
+  lw     $v0,%call16(_foo)($gp)
+bar:
+  lui    $t0,%hi(_gp_disp)
+  addi   $t0,$t0,%lo(_gp_disp)
+
+# EXE:      Disassembly of section .text:
+# EXE-NEXT: __start:
+# EXE-NEXT:  20000:   3c 08 00 02   lui    $8, 2
+#                                              ^-- %hi(0x47ff0-0x20000)
+# EXE-NEXT:  20004:   21 08 80 00   addi   $8, $8, -32768
+#                                                  ^-- %lo(0x38000-0x20004+4)
+# EXE:      bar:
+# EXE-NEXT:  2000c:   3c 08 00 01   lui    $8, 1
+#                                              ^-- %hi(0x38000-0x2000c)
+# EXE-NEXT:  20010:   21 08 7f f4   addi   $8, $8, 32756
+#                                                  ^-- %lo(0x38000-0x20010+4)
+
+# EXE: SYMBOL TABLE:
+# EXE: 0002000c     .text   00000000 bar
+# EXE: 00038000     *ABS*   00000000 .hidden _gp
+# EXE: 00020000     .text   00000000 __start
+
+# SO:      Disassembly of section .text:
+# SO-NEXT: __start:
+# SO-NEXT:  10000:   3c 08 00 02   lui    $8, 2
+#                                             ^-- %hi(0x28000-0x10000)
+# SO-NEXT:  10004:   21 08 80 00   addi   $8, $8, -32768
+#                                                 ^-- %lo(0x28000-0x10004+4)
+# SO:       bar:
+# SO-NEXT:   1000c:   3c 08 00 01   lui    $8, 1
+#                                              ^-- %hi(0x28000-0x1000c)
+# SO-NEXT:   10010:   21 08 7f f4   addi   $8, $8, 32756
+#                                                  ^-- %lo(0x28000-0x10010+4)
+
+# SO: SYMBOL TABLE:
+# SO: 0001000c     .text   00000000 bar
+# SO: 00028000     *ABS*   00000000 .hidden _gp
+# SO: 00010000     .text   00000000 __start
diff --git a/test/ELF/mips-hilo-hi-only.s b/test/ELF/mips-hilo-hi-only.s
new file mode 100644 (file)
index 0000000..97808b5
--- /dev/null
@@ -0,0 +1,28 @@
+# Check warning on orphaned R_MIPS_HI16 relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe 2>&1 | FileCheck -check-prefix=WARN %s
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__start+0x10000)
+  addi   $t0,$t0,%lo(_label)
+_label:
+  nop
+
+# WARN: can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
+#                                                ^-- %hi(__start) w/o addend
+# CHECK-NEXT   20004:   21 08 00 08   addi   $8, $8, 8
+#                                                    ^-- %lo(_label)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00020008    .text   00000000 _label
+# CHECK: 00020000    .text   00000000 __start
diff --git a/test/ELF/mips-hilo.s b/test/ELF/mips-hilo.s
new file mode 100644 (file)
index 0000000..d5de942
--- /dev/null
@@ -0,0 +1,53 @@
+# Check R_MIPS_HI16 / LO16 relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__start)
+  lui    $t1,%hi(g1)
+  addi   $t0,$t0,%lo(__start+4)
+  addi   $t0,$t0,%lo(g1+8)
+
+  lui    $t0,%hi(l1+0x10000)
+  lui    $t1,%hi(l1+0x20000)
+  addi   $t0,$t0,%lo(l1+(-4))
+
+  .data
+  .type  l1,@object
+  .size  l1,4
+l1:
+  .word 0
+
+  .globl g1
+  .type  g1,@object
+  .size  g1,4
+g1:
+  .word 0
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
+#                                                ^-- %hi(__start+4)
+# CHECK-NEXT:  20004:   3c 09 00 03   lui    $9, 3
+#                                                ^-- %hi(g1+8)
+# CHECK-NEXT:  20008:   21 08 00 04   addi   $8, $8, 4
+#                                                    ^-- %lo(__start+4)
+# CHECK-NEXT:  2000c:   21 08 00 0c   addi   $8, $8, 12
+#                                                    ^-- %lo(g1+8)
+# CHECK-NEXT:  20010:   3c 08 00 04   lui    $8, 4
+#                                                ^-- %hi(l1+0x10000-4)
+# CHECK-NEXT:  20014:   3c 09 00 05   lui    $9, 5
+#                                                ^-- %hi(l1+0x20000-4)
+# CHECK-NEXT:  20018:   21 08 ff fc   addi   $8, $8, -4
+#                                                    ^-- %lo(l1-4)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 0030000 l   .data   00000004 l1
+# CHECK: 0020000     .text   00000000 __start
+# CHECK: 0030004 g   .data   00000004 g1
diff --git a/test/ELF/mips-jalr.test b/test/ELF/mips-jalr.test
new file mode 100644 (file)
index 0000000..c1b119c
--- /dev/null
@@ -0,0 +1,52 @@
+# Check that lld ignores R_MIPS_JALR relocation for now.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t.so -shared
+# RUN: llvm-objdump -d %t.so | FileCheck %s
+# RUN: llvm-readobj -relocations %t.so | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# CHECK: 10000:   09 f8 20 03   jalr    $25
+
+# REL:      Relocations [
+# REL-NEXT: ]
+
+!ELF
+FileHeader:
+  Class:    ELFCLASS32
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_MIPS
+  Flags:    [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+  - Name:          .text
+    Type:          SHT_PROGBITS
+    Flags:         [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:  16
+    Content:       "09f82003"
+#                   ^-- jalr T1
+
+  - Name:          .rel.text
+    Type:          SHT_REL
+    Link:          .symtab
+    Info:          .text
+    Relocations:
+      - Offset:  0
+        Symbol:  T1
+        Type:    R_MIPS_JALR
+
+Symbols:
+  Local:
+    - Name:     T1
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0
+      Size:     4
+  Global:
+    - Name:     __start
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0
+      Size:     4
diff --git a/test/ELF/mips-lo16-not-relative.s b/test/ELF/mips-lo16-not-relative.s
new file mode 100644 (file)
index 0000000..614e639
--- /dev/null
@@ -0,0 +1,23 @@
+# Check that R_MIPS_LO16 relocation is handled as non-relative,
+# and if a target symbol is a DSO data symbol, LLD create a copy
+# relocation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rel.dyn {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+  .text
+  .global __start
+__start:
+  addi   $t0, $t0, %lo(data0)
diff --git a/test/ELF/mips-merge-abiflags.s b/test/ELF/mips-merge-abiflags.s
new file mode 100644 (file)
index 0000000..2e8b43b
--- /dev/null
@@ -0,0 +1,63 @@
+# Test that lld handles input files with concatenated .MIPS.abiflags sections
+# This happens e.g. with the FreeBSD BFD (BFD 2.17.50 [FreeBSD] 2007-07-03)
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
+# RUN: ld.lld %t.o %p/Inputs/mips-concatenated-abiflags.o -o %t.exe
+# RUN: llvm-readobj -sections -mips-abi-flags %t.exe | FileCheck %s
+# RUN: llvm-readobj -sections -mips-abi-flags \
+# RUN:     %p/Inputs/mips-concatenated-abiflags.o | \
+# RUN:   FileCheck --check-prefix=INPUT-OBJECT %s
+
+# REQUIRES: mips
+        .globl  __start
+__start:
+        nop
+
+# CHECK:      Section {
+# CHECK:        Index: 1
+# CHECK-NEXT:   Name: .MIPS.abiflags
+# CHECK-NEXT:   Type: SHT_MIPS_ABIFLAGS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 24
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 8
+# CHECK-NEXT:   EntrySize: 24
+# CHECK-NEXT: }
+
+# CHECK:      MIPS ABI Flags {
+# CHECK-NEXT:   Version: 0
+# CHECK-NEXT:   ISA: MIPS64
+# CHECK-NEXT:   ISA Extension: None
+# CHECK-NEXT:   ASEs [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   FP ABI: Hard float (double precision)
+# CHECK-NEXT:   GPR size: 64
+# CHECK-NEXT:   CPR1 size: 64
+# CHECK-NEXT:   CPR2 size: 0
+# CHECK-NEXT:   Flags 1 [
+# CHECK-NEXT:     ODDSPREG
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Flags 2: 0x0
+# CHECK-NEXT: }
+
+# INPUT-OBJECT:       Section {
+# INPUT-OBJECT:         Index: 3
+# INPUT-OBJECT-NEXT:    Name: .MIPS.abiflags
+# INPUT-OBJECT-NEXT:    Type: SHT_MIPS_ABIFLAGS
+# INPUT-OBJECT-NEXT:    Flags [
+# INPUT-OBJECT-NEXT:      SHF_ALLOC
+# INPUT-OBJECT-NEXT:    ]
+# INPUT-OBJECT-NEXT:    Address:
+# INPUT-OBJECT-NEXT:    Offset:
+# INPUT-OBJECT-NEXT:    Size: 48
+# INPUT-OBJECT-NEXT:    Link: 0
+# INPUT-OBJECT-NEXT:    Info: 0
+# INPUT-OBJECT-NEXT:    AddressAlignment: 8
+# INPUT-OBJECT-NEXT:    EntrySize: 0
+# INPUT-OBJECT-NEXT:  }
+# INPUT-OBJECT:       The .MIPS.abiflags section has a wrong size.
diff --git a/test/ELF/mips-n32-emul.s b/test/ELF/mips-n32-emul.s
new file mode 100644 (file)
index 0000000..d0d81cc
--- /dev/null
@@ -0,0 +1,14 @@
+# Check that LLD shows an error when N32 ABI emulation argument
+# is combined with non-N32 ABI object files.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: not ld.lld -m elf32btsmipn32 %t.o -o %t.exe 2>&1 | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .global  __start
+__start:
+  nop
+
+# CHECK: error: {{.*}}mips-n32-emul.s.tmp.o is incompatible with elf32btsmipn32
diff --git a/test/ELF/mips-n32-rels.s b/test/ELF/mips-n32-rels.s
new file mode 100644 (file)
index 0000000..7706e25
--- /dev/null
@@ -0,0 +1,71 @@
+# Check handling of N32 ABI relocation records.
+
+# For now llvm-mc generates incorrect object files for N32 ABI.
+# We use the binary input file generated by GNU tool.
+# llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+#         -target-abi n32 %s -o %t.o
+# RUN: ld.lld %S/Inputs/mips-n32-rels.o -o %t.exe
+# RUN: llvm-objdump -t -d -s %t.exe | FileCheck %s
+# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=ELF %s
+
+# REQUIRES: mips
+
+#   .text
+#   .type   __start, @function
+#   .global  __start
+# __start:
+#   lui     $gp,%hi(%neg(%gp_rel(__start)))     # R_MIPS_GPREL16
+#                                               # R_MIPS_SUB
+#                                               # R_MIPS_HI16
+# loc:
+#   daddiu  $gp,$gp,%lo(%neg(%gp_rel(__start))) # R_MIPS_GPREL16
+#                                               # R_MIPS_SUB
+#                                               # R_MIPS_LO16
+#
+#   .section  .rodata,"a",@progbits
+#   .gpword(loc)                                # R_MIPS_32
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:  3c 1c 00 01  lui     $gp, 1
+#                                                  ^-- 0x20000 - 0x37ff0
+#                                                  ^-- 0 - 0xfffe8010
+#                                                  ^-- %hi(0x17ff0)
+# CHECK:      loc:
+# CHECK-NEXT:    20004:  67 9c 7f f0  daddiu  $gp, $gp, 32752
+#                                                       ^-- 0x20000 - 0x37ff0
+#                                                       ^-- 0 - 0xfffe8010
+#                                                       ^-- %lo(0x17ff0)
+
+# CHECK:      Contents of section .rodata:
+# CHECK-NEXT:  100d4 00020004
+#                    ^-- loc
+
+# CHECK: 00020004      .text   00000000 loc
+# CHECK: 00037ff0      *ABS*   00000000 .hidden _gp
+# CHECK: 00020000 g  F .text   00000000 __start
+
+# ELF:      Format: ELF32-mips
+# ELF-NEXT: Arch: mips
+# ELF-NEXT: AddressSize: 32bit
+# ELF-NEXT: LoadName:
+# ELF-NEXT: ElfHeader {
+# ELF-NEXT:   Ident {
+# ELF-NEXT:     Magic: (7F 45 4C 46)
+# ELF-NEXT:     Class: 32-bit (0x1)
+# ELF-NEXT:     DataEncoding: BigEndian (0x2)
+# ELF-NEXT:     FileVersion: 1
+# ELF-NEXT:     OS/ABI: SystemV (0x0)
+# ELF-NEXT:     ABIVersion: 0
+# ELF-NEXT:     Unused: (00 00 00 00 00 00 00)
+# ELF-NEXT:   }
+# ELF-NEXT:   Type: Executable (0x2)
+# ELF-NEXT:   Machine: EM_MIPS (0x8)
+# ELF-NEXT:   Version: 1
+# ELF-NEXT:   Entry: 0x20000
+# ELF-NEXT:   ProgramHeaderOffset:
+# ELF-NEXT:   SectionHeaderOffset:
+# ELF-NEXT:   Flags [
+# ELF-NEXT:     EF_MIPS_ABI2
+# ELF-NEXT:     EF_MIPS_ARCH_64R2
+# ELF-NEXT:   ]
diff --git a/test/ELF/mips-no-objects.s b/test/ELF/mips-no-objects.s
new file mode 100644 (file)
index 0000000..444477e
--- /dev/null
@@ -0,0 +1,5 @@
+# REQUIRES: mips
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: ld.lld %t.so -shared -o %t2.so
+# RUN: llvm-readobj %t2.so > /dev/null 2>&1
diff --git a/test/ELF/mips-nonalloc.s b/test/ELF/mips-nonalloc.s
new file mode 100644 (file)
index 0000000..7b0aa94
--- /dev/null
@@ -0,0 +1,21 @@
+# Check reading addends for relocations in non-allocatable sections.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-nonalloc.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Contents of section .debug_info:
+# CHECK-NEXT:  0000 ffffffff 00020000 00020000
+#                            ^--------^-- __start
+
+  .global __start
+__start:
+  nop
+
+.section .debug_info
+  .word 0xffffffff
+  .word __start
diff --git a/test/ELF/mips-npic-call-pic-os.s b/test/ELF/mips-npic-call-pic-os.s
new file mode 100644 (file)
index 0000000..aea0fa1
--- /dev/null
@@ -0,0 +1,138 @@
+# REQUIRES: mips
+# Check LA25 stubs creation with caller in different Output Section to callee.
+# This stub code is necessary when non-PIC code calls PIC function.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-fpic.s -o %t-fpic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-fnpic.s -o %t-fnpic.o
+# RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-pic.s -o %t-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o
+# RUN: ld.lld %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: __LA25Thunk_foo1a:
+# CHECK-NEXT:    20000:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20004:       08 00 80 08     j       131104 <foo1a>
+# CHECK-NEXT:    20008:       27 39 00 20     addiu   $25, $25, 32
+# CHECK-NEXT:    2000c:       00 00 00 00     nop
+# CHECK: __LA25Thunk_foo1b:
+# CHECK-NEXT:    20010:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20014:       08 00 80 09     j       131108 <foo1b>
+# CHECK-NEXT:    20018:       27 39 00 24     addiu   $25, $25, 36
+# CHECK-NEXT:    2001c:       00 00 00 00     nop
+# CHECK: foo1a:
+# CHECK-NEXT:    20020:       00 00 00 00     nop
+# CHECK: foo1b:
+# CHECK-NEXT:    20024:       00 00 00 00     nop
+# CHECK: __LA25Thunk_foo2:
+# CHECK-NEXT:    20028:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    2002c:       08 00 80 10     j       131136 <foo2>
+# CHECK-NEXT:    20030:       27 39 00 40     addiu   $25, $25, 64
+# CHECK-NEXT:    20034:       00 00 00 00     nop
+# CHECK-NEXT:    20038:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2003c:       ef ef ef ef     <unknown>
+# CHECK: foo2:
+# CHECK-NEXT:    20040:       00 00 00 00     nop
+# CHECK: __LA25Thunk_fpic:
+# CHECK-NEXT:    20044:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20048:       08 00 80 18     j       131168 <fpic>
+# CHECK-NEXT:    2004c:       27 39 00 60     addiu   $25, $25, 96
+# CHECK-NEXT:    20050:       00 00 00 00     nop
+# CHECK-NEXT:    20054:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20058:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2005c:       ef ef ef ef     <unknown>
+# CHECK: fpic:
+# CHECK-NEXT:    20060:       00 00 00 00     nop
+# CHECK-NEXT:    20064:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20068:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2006c:       ef ef ef ef     <unknown>
+# CHECK: fnpic:
+# CHECK-NEXT:    20070:       00 00 00 00     nop
+# CHECK-NEXT: Disassembly of section differentos:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20074:       0c 00 80 00     jal     131072 <__LA25Thunk_foo1a>
+# CHECK-NEXT:    20078:       00 00 00 00     nop
+# CHECK-NEXT:    2007c:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# CHECK-NEXT:    20080:       00 00 00 00     nop
+# CHECK-NEXT:    20084:       0c 00 80 04     jal     131088 <__LA25Thunk_foo1b>
+# CHECK-NEXT:    20088:       00 00 00 00     nop
+# CHECK-NEXT:    2008c:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# CHECK-NEXT:    20090:       00 00 00 00     nop
+# CHECK-NEXT:    20094:       0c 00 80 11     jal     131140 <__LA25Thunk_fpic>
+# CHECK-NEXT:    20098:       00 00 00 00     nop
+# CHECK-NEXT:    2009c:       0c 00 80 1c     jal     131184 <fnpic>
+# CHECK-NEXT:    200a0:       00 00 00 00     nop
+
+# Make sure the thunks are created properly no matter how
+# objects are laid out.
+#
+# RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s
+
+# REVERSE: Disassembly of section .text:
+# REVERSE-NEXT: __LA25Thunk_foo1a:
+# REVERSE-NEXT:    20000:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    20004:       08 00 80 08     j       131104 <foo1a>
+# REVERSE-NEXT:    20008:       27 39 00 20     addiu   $25, $25, 32
+# REVERSE-NEXT:    2000c:       00 00 00 00     nop
+# REVERSE: __LA25Thunk_foo1b:
+# REVERSE-NEXT:    20010:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    20014:       08 00 80 09     j       131108 <foo1b>
+# REVERSE-NEXT:    20018:       27 39 00 24     addiu   $25, $25, 36
+# REVERSE-NEXT:    2001c:       00 00 00 00     nop
+# REVERSE: foo1a:
+# REVERSE-NEXT:    20020:       00 00 00 00     nop
+# REVERSE: foo1b:
+# REVERSE-NEXT:    20024:       00 00 00 00     nop
+# REVERSE: __LA25Thunk_foo2:
+# REVERSE-NEXT:    20028:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    2002c:       08 00 80 10     j       131136 <foo2>
+# REVERSE-NEXT:    20030:       27 39 00 40     addiu   $25, $25, 64
+# REVERSE-NEXT:    20034:       00 00 00 00     nop
+# REVERSE-NEXT:    20038:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    2003c:       ef ef ef ef     <unknown>
+# REVERSE: foo2:
+# REVERSE-NEXT:    20040:       00 00 00 00     nop
+# REVERSE-NEXT:    20044:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    20048:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    2004c:       ef ef ef ef     <unknown>
+# REVERSE: __LA25Thunk_fpic:
+# REVERSE-NEXT:    20050:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    20054:       08 00 80 18     j       131168 <fpic>
+# REVERSE-NEXT:    20058:       27 39 00 60     addiu   $25, $25, 96
+# REVERSE-NEXT:    2005c:       00 00 00 00     nop
+# REVERSE: fpic:
+# REVERSE-NEXT:    20060:       00 00 00 00     nop
+# REVERSE-NEXT:    20064:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    20068:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    2006c:       ef ef ef ef     <unknown>
+# REVERSE: fnpic:
+# REVERSE-NEXT:    20070:       00 00 00 00     nop
+# REVERSE-NEXT: Disassembly of section differentos:
+# REVERSE-NEXT: __start:
+# REVERSE-NEXT:    20074:       0c 00 80 00     jal     131072 <__LA25Thunk_foo1a>
+# REVERSE-NEXT:    20078:       00 00 00 00     nop
+# REVERSE-NEXT:    2007c:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# REVERSE-NEXT:    20080:       00 00 00 00     nop
+# REVERSE-NEXT:    20084:       0c 00 80 04     jal     131088 <__LA25Thunk_foo1b>
+# REVERSE-NEXT:    20088:       00 00 00 00     nop
+# REVERSE-NEXT:    2008c:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# REVERSE-NEXT:    20090:       00 00 00 00     nop
+# REVERSE-NEXT:    20094:       0c 00 80 14     jal     131152 <__LA25Thunk_fpic>
+# REVERSE-NEXT:    20098:       00 00 00 00     nop
+# REVERSE-NEXT:    2009c:       0c 00 80 1c     jal     131184 <fnpic>
+# REVERSE-NEXT:    200a0:       00 00 00 00     nop
+
+  .section differentos, "ax", %progbits
+  .globl __start
+__start:
+  jal foo1a
+  jal foo2
+  jal foo1b
+  jal foo2
+  jal fpic
+  jal fnpic
diff --git a/test/ELF/mips-npic-call-pic-script.s b/test/ELF/mips-npic-call-pic-script.s
new file mode 100644 (file)
index 0000000..2307044
--- /dev/null
@@ -0,0 +1,255 @@
+# REQUIRES: mips
+# Check LA25 stubs creation. This stub code is necessary when
+# non-PIC code calls PIC function.
+# RUN: echo "SECTIONS { .out 0x20000 : { *(.text.*) . = . + 0x100 ;  *(.text) }  }" > %t1.script
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-fpic.s -o %t-fpic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-fnpic.s -o %t-fnpic.o
+# RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-pic.s -o %t-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o
+# RUN: ld.lld --script %t1.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: Disassembly of section .out:
+# CHECK-NEXT: __LA25Thunk_foo1a:
+# CHECK-NEXT:    20000:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20004:       08 00 80 08     j       131104 <foo1a>
+# CHECK-NEXT:    20008:       27 39 00 20     addiu   $25, $25, 32
+# CHECK-NEXT:    2000c:       00 00 00 00     nop
+# CHECK: __LA25Thunk_foo1b:
+# CHECK-NEXT:    20010:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20014:       08 00 80 09     j       131108 <foo1b>
+# CHECK-NEXT:    20018:       27 39 00 24     addiu   $25, $25, 36
+# CHECK-NEXT:    2001c:       00 00 00 00     nop
+# CHECK: foo1a:
+# CHECK-NEXT:    20020:       00 00 00 00     nop
+# CHECK: foo1b:
+# CHECK-NEXT:    20024:       00 00 00 00     nop
+# CHECK: __LA25Thunk_foo2:
+# CHECK-NEXT:    20028:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    2002c:       08 00 80 10     j       131136 <foo2>
+# CHECK-NEXT:    20030:       27 39 00 40     addiu   $25, $25, 64
+# CHECK-NEXT:    20034:       00 00 00 00     nop
+# CHECK-NEXT:    20038:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2003c:       ef ef ef ef     <unknown>
+# CHECK: foo2:
+# CHECK-NEXT:    20040:       00 00 00 00     nop
+# CHECK-NEXT:    20044:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20048:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2004c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20050:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20054:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20058:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2005c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20060:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20064:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20068:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2006c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20070:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20074:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20078:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2007c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20080:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20084:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20088:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2008c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20090:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20094:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20098:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2009c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200a0:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200a4:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200a8:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200ac:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200b0:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200b4:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200b8:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200bc:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200c0:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200c4:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200c8:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200cc:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200d0:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200d4:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200d8:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200dc:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200e0:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200e4:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200e8:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200ec:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200f0:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200f4:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200f8:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    200fc:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20100:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20104:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20108:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2010c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20110:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20114:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20118:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2011c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20120:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20124:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20128:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2012c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20130:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20134:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20138:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2013c:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20140:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20144:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20148:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2014c:       ef ef ef ef     <unknown>
+# CHECK: __start:
+# CHECK-NEXT:    20150:       0c 00 80 00     jal     131072 <__LA25Thunk_foo1a>
+# CHECK-NEXT:    20154:       00 00 00 00     nop
+# CHECK-NEXT:    20158:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# CHECK-NEXT:    2015c:       00 00 00 00     nop
+# CHECK-NEXT:    20160:       0c 00 80 04     jal     131088 <__LA25Thunk_foo1b>
+# CHECK-NEXT:    20164:       00 00 00 00     nop
+# CHECK-NEXT:    20168:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# CHECK-NEXT:    2016c:       00 00 00 00     nop
+# CHECK-NEXT:    20170:       0c 00 80 60     jal     131456 <__LA25Thunk_fpic>
+# CHECK-NEXT:    20174:       00 00 00 00     nop
+# CHECK-NEXT:    20178:       0c 00 80 68     jal     131488 <fnpic>
+# CHECK-NEXT:    2017c:       00 00 00 00     nop
+# CHECK: __LA25Thunk_fpic:
+# CHECK-NEXT:    20180:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20184:       08 00 80 64     j       131472 <fpic>
+# CHECK-NEXT:    20188:       27 39 01 90     addiu   $25, $25, 400
+# CHECK-NEXT:    2018c:       00 00 00 00     nop
+# CHECK: fpic:
+# CHECK-NEXT:    20190:       00 00 00 00     nop
+# CHECK-NEXT:    20194:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20198:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2019c:       ef ef ef ef     <unknown>
+# CHECK: fnpic:
+# CHECK-NEXT:    201a0:       00 00 00 00     nop
+
+  .text
+  .globl __start
+__start:
+  jal foo1a
+  jal foo2
+  jal foo1b
+  jal foo2
+  jal fpic
+  jal fnpic
+
+# Test script with orphans added to existing OutputSection, the .text.1 and
+# .text.2 sections will be added to .text
+# RUN: echo "SECTIONS { .text 0x20000 : { *(.text) }  }" > %t2.script
+# RUN: ld.lld --script %t2.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t2.exe
+# RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=ORPH1 %s
+# ORPH1: Disassembly of section .text:
+# ORPH1-NEXT: __start:
+# ORPH1-NEXT:    20000:       0c 00 80 15     jal     131156 <__LA25Thunk_foo1a>
+# ORPH1-NEXT:    20004:       00 00 00 00     nop
+# ORPH1-NEXT:    20008:       0c 00 80 22     jal     131208 <__LA25Thunk_foo2>
+# ORPH1-NEXT:    2000c:       00 00 00 00     nop
+# ORPH1-NEXT:    20010:       0c 00 80 19     jal     131172 <__LA25Thunk_foo1b>
+# ORPH1-NEXT:    20014:       00 00 00 00     nop
+# ORPH1-NEXT:    20018:       0c 00 80 22     jal     131208 <__LA25Thunk_foo2>
+# ORPH1-NEXT:    2001c:       00 00 00 00     nop
+# ORPH1-NEXT:    20020:       0c 00 80 0c     jal     131120 <__LA25Thunk_fpic>
+# ORPH1-NEXT:    20024:       00 00 00 00     nop
+# ORPH1-NEXT:    20028:       0c 00 80 14     jal     131152 <fnpic>
+# ORPH1-NEXT:    2002c:       00 00 00 00     nop
+# ORPH1: __LA25Thunk_fpic:
+# ORPH1-NEXT:    20030:       3c 19 00 02     lui     $25, 2
+# ORPH1-NEXT:    20034:       08 00 80 10     j       131136 <fpic>
+# ORPH1-NEXT:    20038:       27 39 00 40     addiu   $25, $25, 64
+# ORPH1-NEXT:    2003c:       00 00 00 00     nop
+# ORPH1: fpic:
+# ORPH1-NEXT:    20040:       00 00 00 00     nop
+# ORPH1-NEXT:    20044:       ef ef ef ef     <unknown>
+# ORPH1-NEXT:    20048:       ef ef ef ef     <unknown>
+# ORPH1-NEXT:    2004c:       ef ef ef ef     <unknown>
+# ORPH1: fnpic:
+# ORPH1-NEXT:    20050:       00 00 00 00     nop
+# ORPH1: __LA25Thunk_foo1a:
+# ORPH1-NEXT:    20054:       3c 19 00 02     lui     $25, 2
+# ORPH1-NEXT:    20058:       08 00 80 20     j       131200 <foo1a>
+# ORPH1-NEXT:    2005c:       27 39 00 80     addiu   $25, $25, 128
+# ORPH1-NEXT:    20060:       00 00 00 00     nop
+# ORPH1: __LA25Thunk_foo1b:
+# ORPH1-NEXT:    20064:       3c 19 00 02     lui     $25, 2
+# ORPH1-NEXT:    20068:       08 00 80 21     j       131204 <foo1b>
+# ORPH1-NEXT:    2006c:       27 39 00 84     addiu   $25, $25, 132
+# ORPH1-NEXT:    20070:       00 00 00 00     nop
+# ORPH1-NEXT:    20074:       ef ef ef ef     <unknown>
+# ORPH1-NEXT:    20078:       ef ef ef ef     <unknown>
+# ORPH1-NEXT:    2007c:       ef ef ef ef     <unknown>
+# ORPH1: foo1a:
+# ORPH1-NEXT:    20080:       00 00 00 00     nop
+# ORPH1: foo1b:
+# ORPH1-NEXT:    20084:       00 00 00 00     nop
+# ORPH1: __LA25Thunk_foo2:
+# ORPH1-NEXT:    20088:       3c 19 00 02     lui     $25, 2
+# ORPH1-NEXT:    2008c:       08 00 80 28     j       131232 <foo2>
+# ORPH1-NEXT:    20090:       27 39 00 a0     addiu   $25, $25, 160
+# ORPH1-NEXT:    20094:       00 00 00 00     nop
+# ORPH1-NEXT:    20098:       ef ef ef ef     <unknown>
+# ORPH1-NEXT:    2009c:       ef ef ef ef     <unknown>
+# ORPH1: foo2:
+# ORPH1-NEXT:    200a0:       00 00 00 00     nop
+
+# Test script with orphans added to new OutputSection, the .text.1 and
+# .text.2 sections will form a new OutputSection .text
+# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) }  }" > %t3.script
+# RUN: ld.lld --script %t3.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t3.exe
+# RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=ORPH2 %s
+# ORPH2: Disassembly of section .out:
+# ORPH2-NEXT: __start:
+# ORPH2-NEXT:    20000:       0c 00 80 18     jal     131168 <__LA25Thunk_foo1a>
+# ORPH2-NEXT:    20004:       00 00 00 00     nop
+# ORPH2-NEXT:    20008:       0c 00 80 22     jal     131208 <__LA25Thunk_foo2>
+# ORPH2-NEXT:    2000c:       00 00 00 00     nop
+# ORPH2-NEXT:    20010:       0c 00 80 1c     jal     131184 <__LA25Thunk_foo1b>
+# ORPH2-NEXT:    20014:       00 00 00 00     nop
+# ORPH2-NEXT:    20018:       0c 00 80 22     jal     131208 <__LA25Thunk_foo2>
+# ORPH2-NEXT:    2001c:       00 00 00 00     nop
+# ORPH2-NEXT:    20020:       0c 00 80 0c     jal     131120 <__LA25Thunk_fpic>
+# ORPH2-NEXT:    20024:       00 00 00 00     nop
+# ORPH2-NEXT:    20028:       0c 00 80 14     jal     131152 <fnpic>
+# ORPH2-NEXT:    2002c:       00 00 00 00     nop
+# ORPH2: __LA25Thunk_fpic:
+# ORPH2-NEXT:    20030:       3c 19 00 02     lui     $25, 2
+# ORPH2-NEXT:    20034:       08 00 80 10     j       131136 <fpic>
+# ORPH2-NEXT:    20038:       27 39 00 40     addiu   $25, $25, 64
+# ORPH2-NEXT:    2003c:       00 00 00 00     nop
+# ORPH2: fpic:
+# ORPH2-NEXT:    20040:       00 00 00 00     nop
+# ORPH2-NEXT:    20044:       ef ef ef ef     <unknown>
+# ORPH2-NEXT:    20048:       ef ef ef ef     <unknown>
+# ORPH2-NEXT:    2004c:       ef ef ef ef     <unknown>
+# ORPH2: fnpic:
+# ORPH2-NEXT:    20050:       00 00 00 00     nop
+# ORPH2-NEXT: Disassembly of section .text:
+# ORPH2-NEXT: __LA25Thunk_foo1a:
+# ORPH2-NEXT:    20060:       3c 19 00 02     lui     $25, 2
+# ORPH2-NEXT:    20064:       08 00 80 20     j       131200 <foo1a>
+# ORPH2-NEXT:    20068:       27 39 00 80     addiu   $25, $25, 128
+# ORPH2-NEXT:    2006c:       00 00 00 00     nop
+# ORPH2: __LA25Thunk_foo1b:
+# ORPH2-NEXT:    20070:       3c 19 00 02     lui     $25, 2
+# ORPH2-NEXT:    20074:       08 00 80 21     j       131204 <foo1b>
+# ORPH2-NEXT:    20078:       27 39 00 84     addiu   $25, $25, 132
+# ORPH2-NEXT:    2007c:       00 00 00 00     nop
+# ORPH2: foo1a:
+# ORPH2-NEXT:    20080:       00 00 00 00     nop
+# ORPH2: foo1b:
+# ORPH2-NEXT:    20084:       00 00 00 00     nop
+# ORPH2: __LA25Thunk_foo2:
+# ORPH2-NEXT:    20088:       3c 19 00 02     lui     $25, 2
+# ORPH2-NEXT:    2008c:       08 00 80 28     j       131232 <foo2>
+# ORPH2-NEXT:    20090:       27 39 00 a0     addiu   $25, $25, 160
+# ORPH2-NEXT:    20094:       00 00 00 00     nop
+# ORPH2-NEXT:    20098:       ef ef ef ef     <unknown>
+# ORPH2-NEXT:    2009c:       ef ef ef ef     <unknown>
+# ORPH2: foo2:
+# ORPH2-NEXT:    200a0:       00 00 00 00     nop
diff --git a/test/ELF/mips-npic-call-pic.s b/test/ELF/mips-npic-call-pic.s
new file mode 100644 (file)
index 0000000..c3c94d7
--- /dev/null
@@ -0,0 +1,145 @@
+# REQUIRES: mips
+# Check LA25 stubs creation. This stub code is necessary when
+# non-PIC code calls PIC function.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-fpic.s -o %t-fpic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-fnpic.s -o %t-fnpic.o
+# RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-pic.s -o %t-pic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o
+# RUN: ld.lld %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK:     Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:       0c 00 80 0c     jal     131120 <__LA25Thunk_foo1a>
+# CHECK-NEXT:    20004:       00 00 00 00     nop
+# CHECK-NEXT:    20008:       0c 00 80 16     jal     131160 <__LA25Thunk_foo2>
+# CHECK-NEXT:    2000c:       00 00 00 00     nop
+# CHECK-NEXT:    20010:       0c 00 80 10     jal     131136 <__LA25Thunk_foo1b>
+# CHECK-NEXT:    20014:       00 00 00 00     nop
+# CHECK-NEXT:    20018:       0c 00 80 16     jal     131160 <__LA25Thunk_foo2>
+# CHECK-NEXT:    2001c:       00 00 00 00     nop
+# CHECK-NEXT:    20020:       0c 00 80 1d     jal     131188 <__LA25Thunk_fpic>
+# CHECK-NEXT:    20024:       00 00 00 00     nop
+# CHECK-NEXT:    20028:       0c 00 80 28     jal     131232 <fnpic>
+# CHECK-NEXT:    2002c:       00 00 00 00     nop
+#
+# CHECK: __LA25Thunk_foo1a:
+# CHECK-NEXT:    20030:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20034:       08 00 80 14     j       131152 <foo1a>
+# CHECK-NEXT:    20038:       27 39 00 50     addiu   $25, $25, 80
+# CHECK-NEXT:    2003c:       00 00 00 00     nop
+
+# CHECK: __LA25Thunk_foo1b:
+# CHECK-NEXT:    20040:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20044:       08 00 80 15     j       131156 <foo1b>
+# CHECK-NEXT:    20048:       27 39 00 54     addiu   $25, $25, 84
+# CHECK-NEXT:    2004c:       00 00 00 00     nop
+
+# CHECK: foo1a:
+# CHECK-NEXT:    20050:       00 00 00 00     nop
+
+# CHECK: foo1b:
+# CHECK-NEXT:    20054:       00 00 00 00     nop
+
+# CHECK: __LA25Thunk_foo2:
+# CHECK-NEXT:    20058:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    2005c:       08 00 80 1c     j       131184 <foo2>
+# CHECK-NEXT:    20060:       27 39 00 70     addiu   $25, $25, 112
+# CHECK-NEXT:    20064:       00 00 00 00     nop
+# CHECK-NEXT:    20068:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2006c:       ef ef ef ef     <unknown>
+
+# CHECK: foo2:
+# CHECK-NEXT:    20070:       00 00 00 00     nop
+
+# CHECK: __LA25Thunk_fpic:
+# CHECK-NEXT:    20074:       3c 19 00 02     lui     $25, 2
+# CHECK-NEXT:    20078:       08 00 80 24     j       131216 <fpic>
+# CHECK-NEXT:    2007c:       27 39 00 90     addiu   $25, $25, 144
+# CHECK-NEXT:    20080:       00 00 00 00     nop
+# CHECK-NEXT:    20084:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20088:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2008c:       ef ef ef ef     <unknown>
+
+# CHECK: fpic:
+# CHECK-NEXT:    20090:       00 00 00 00     nop
+# CHECK-NEXT:    20094:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    20098:       ef ef ef ef     <unknown>
+# CHECK-NEXT:    2009c:       ef ef ef ef     <unknown>
+
+# CHECK: fnpic:
+# CHECK-NEXT:    200a0:       00 00 00 00     nop
+
+# Make sure the thunks are created properly no matter how
+# objects are laid out.
+#
+# RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s
+
+# REVERSE: Disassembly of section .text:
+# REVERSE-NEXT: __LA25Thunk_foo1a:
+# REVERSE-NEXT:    20000:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    20004:       08 00 80 08     j       131104 <foo1a>
+# REVERSE-NEXT:    20008:       27 39 00 20     addiu   $25, $25, 32
+# REVERSE-NEXT:    2000c:       00 00 00 00     nop
+# REVERSE: __LA25Thunk_foo1b:
+# REVERSE-NEXT:    20010:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    20014:       08 00 80 09     j       131108 <foo1b>
+# REVERSE-NEXT:    20018:       27 39 00 24     addiu   $25, $25, 36
+# REVERSE-NEXT:    2001c:       00 00 00 00     nop
+# REVERSE: foo1a:
+# REVERSE-NEXT:    20020:       00 00 00 00     nop
+# REVERSE: foo1b:
+# REVERSE-NEXT:    20024:       00 00 00 00     nop
+# REVERSE: __LA25Thunk_foo2:
+# REVERSE-NEXT:    20028:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    2002c:       08 00 80 10     j       131136 <foo2>
+# REVERSE-NEXT:    20030:       27 39 00 40     addiu   $25, $25, 64
+# REVERSE-NEXT:    20034:       00 00 00 00     nop
+# REVERSE-NEXT:    20038:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    2003c:       ef ef ef ef     <unknown>
+# REVERSE: foo2:
+# REVERSE-NEXT:    20040:       00 00 00 00     nop
+# REVERSE-NEXT:    20044:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    20048:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    2004c:       ef ef ef ef     <unknown>
+# REVERSE: __start:
+# REVERSE-NEXT:    20050:       0c 00 80 00     jal     131072 <__LA25Thunk_foo1a>
+# REVERSE-NEXT:    20054:       00 00 00 00     nop
+# REVERSE-NEXT:    20058:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# REVERSE-NEXT:    2005c:       00 00 00 00     nop
+# REVERSE-NEXT:    20060:       0c 00 80 04     jal     131088 <__LA25Thunk_foo1b>
+# REVERSE-NEXT:    20064:       00 00 00 00     nop
+# REVERSE-NEXT:    20068:       0c 00 80 0a     jal     131112 <__LA25Thunk_foo2>
+# REVERSE-NEXT:    2006c:       00 00 00 00     nop
+# REVERSE-NEXT:    20070:       0c 00 80 20     jal     131200 <__LA25Thunk_fpic>
+# REVERSE-NEXT:    20074:       00 00 00 00     nop
+# REVERSE-NEXT:    20078:       0c 00 80 28     jal     131232 <fnpic>
+# REVERSE-NEXT:    2007c:       00 00 00 00     nop
+# REVERSE: __LA25Thunk_fpic:
+# REVERSE-NEXT:    20080:       3c 19 00 02     lui     $25, 2
+# REVERSE-NEXT:    20084:       08 00 80 24     j       131216 <fpic>
+# REVERSE-NEXT:    20088:       27 39 00 90     addiu   $25, $25, 144
+# REVERSE-NEXT:    2008c:       00 00 00 00     nop
+# REVERSE: fpic:
+# REVERSE-NEXT:    20090:       00 00 00 00     nop
+# REVERSE-NEXT:    20094:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    20098:       ef ef ef ef     <unknown>
+# REVERSE-NEXT:    2009c:       ef ef ef ef     <unknown>
+# REVERSE: fnpic:
+# REVERSE-NEXT:    200a0:       00 00 00 00     nop
+
+  .text
+  .globl __start
+__start:
+  jal foo1a
+  jal foo2
+  jal foo1b
+  jal foo2
+  jal fpic
+  jal fnpic
diff --git a/test/ELF/mips-options-r.test b/test/ELF/mips-options-r.test
new file mode 100644 (file)
index 0000000..40c61c0
--- /dev/null
@@ -0,0 +1,18 @@
+# Check that if input file contains .MIPS.options section and symbol
+# points to the section and the linker generates a relocatable output,
+# LLD does not crash.
+#
+# PR 27878
+#
+# Input object file created using the following script:
+# % cat t.s
+#   .text
+#   nop
+# % as -mabi=64 -mips64r2 t.s
+
+# RUN: ld.lld -r %p/Inputs/mips-options.o -o %t.o
+# RUN: llvm-readobj -s %t.o | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK: Name: .MIPS.options
diff --git a/test/ELF/mips-options.s b/test/ELF/mips-options.s
new file mode 100644 (file)
index 0000000..18f5af8
--- /dev/null
@@ -0,0 +1,31 @@
+# Check MIPS .MIPS.options section generation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: echo "SECTIONS { \
+# RUN:          . = 0x100000000; \
+# RUN:          .got  : { *(.got) } }" > %t.rel.script
+# RUN: ld.lld %t1.o %t2.o --gc-sections --script %t.rel.script -shared -o %t.so
+# RUN: llvm-readobj -symbols -mips-options %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+    lui  $gp, %hi(%neg(%gp_rel(g1)))
+
+# CHECK:      Name: _gp
+# CHECK-NEXT: Value: 0x[[GP:[0-9A-F]+]]
+
+# CHECK:      MIPS Options {
+# CHECK-NEXT:   ODK_REGINFO {
+# CHECK-NEXT:     GP: 0x[[GP]]
+# CHECK-NEXT:     General Mask: 0x10000001
+# CHECK-NEXT:     Co-Proc Mask0: 0x0
+# CHECK-NEXT:     Co-Proc Mask1: 0x0
+# CHECK-NEXT:     Co-Proc Mask2: 0x0
+# CHECK-NEXT:     Co-Proc Mask3: 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: }
diff --git a/test/ELF/mips-pc-relocs.s b/test/ELF/mips-pc-relocs.s
new file mode 100644 (file)
index 0000000..e0f39e7
--- /dev/null
@@ -0,0 +1,45 @@
+# Check R_MIPS_PCxxx relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -mcpu=mips32r6 -d -t -s %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lwpc      $6, _foo                # R_MIPS_PC19_S2
+  beqc      $5, $6, _foo            # R_MIPS_PC16
+  beqzc     $9, _foo                # R_MIPS_PC21_S2
+  bc        _foo                    # R_MIPS_PC26_S2
+  aluipc    $2, %pcrel_hi(_foo)     # R_MIPS_PCHI16
+  addiu     $2, $2, %pcrel_lo(_foo) # R_MIPS_PCLO16
+
+  .data
+  .word _foo+8-.                    # R_MIPS_PC32
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:       ec c8 00 08     lwpc    $6, 32
+#                                      ^-- (0x20020-0x20000)>>2
+# CHECK-NEXT:    20004:       20 a6 00 06     beqc    $5, $6, 28
+#                                      ^-- (0x20020-4-0x20004)>>2
+# CHECK-NEXT:    20008:       d9 20 00 05     beqzc   $9, 24
+#                                      ^-- (0x20020-4-0x20008)>>2
+# CHECK-NEXT:    2000c:       c8 00 00 04     bc      20
+#                                      ^-- (0x20020-4-0x2000c)>>2
+# CHECK-NEXT:    20010:       ec 5f 00 00     aluipc  $2, 0
+#                                      ^-- %hi(0x20020-0x20010)
+# CHECK-NEXT:    20014:       24 42 00 0c     addiu   $2, $2, 12
+#                                      ^-- %lo(0x20020-0x20014)
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 30000 ffff0028 00000000 00000000 00000000
+#                   ^-- 0x20020 + 8 - 0x30000
+
+# CHECK: 00020000         .text           00000000 __start
+# CHECK: 00020020         .text           00000000 _foo
diff --git a/test/ELF/mips-plt-copy.s b/test/ELF/mips-plt-copy.s
new file mode 100644 (file)
index 0000000..58883d8
--- /dev/null
@@ -0,0 +1,85 @@
+# Check creating of R_MIPS_COPY and R_MIPS_JUMP_SLOT dynamic relocations
+# and corresponding PLT entries.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section ({{.*}}) .rel.plt {
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
+# CHECK-NEXT:     0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK:      Primary GOT {
+# CHECK:        Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
+
+# CHECK:      PLT GOT {
+# CHECK:        Entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Initial: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Value: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Initial: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Value: 0x{{[0-9A-F]+}}
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo1
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT: }
+
+  .text
+  .globl __start
+__start:
+  lui    $t0,%hi(foo0)     # R_MIPS_HI16 requires JUMP_SLOT/PLT entry
+                           # for DSO defined func.
+  addi   $t0,$t0,%lo(foo0)
+  lui    $t0,%hi(bar)      # Does not require PLT for locally defined func.
+  addi   $t0,$t0,%lo(bar)
+  lui    $t0,%hi(loc)      # Does not require PLT for local func.
+  addi   $t0,$t0,%lo(loc)
+
+  lui    $t0,%hi(data0)    # R_MIPS_HI16 requires COPY rel for DSO defined data.
+  addi   $t0,$t0,%lo(data0)
+  lui    $t0,%hi(gd)       # Does not require COPY rel for locally defined data.
+  addi   $t0,$t0,%lo(gd)
+  lui    $t0,%hi(ld)       # Does not require COPY rel for local data.
+  addi   $t0,$t0,%lo(ld)
+
+  .globl bar
+  .type  bar, @function
+bar:
+  nop
+loc:
+  nop
+
+  .rodata
+  .globl gd
+gd:
+  .word 0
+ld:
+  .word data1+8            # R_MIPS_32 requires REL32 dnamic relocation
+                           # for DSO defined data. For now we generate COPY one.
+  .word foo1+8             # R_MIPS_32 requires PLT entry for DSO defined func.
diff --git a/test/ELF/mips-plt-r6.s b/test/ELF/mips-plt-r6.s
new file mode 100644 (file)
index 0000000..4bab21c
--- /dev/null
@@ -0,0 +1,38 @@
+# Check PLT entries generation in case of R6 ABI version.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         -mcpu=mips32r6 %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t2.o -shared -o %t.so
+# RUN: ld.lld %t1.o %t.so -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:   20000:       0c 00 80 0c     jal     131120
+#                                                    ^-- 0x20030 gotplt[foo0]
+# CHECK-NEXT:   20004:       00 00 00 00     nop
+#
+# CHECK-NEXT: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# CHECK-NEXT:   20010:       3c 1c 00 03     aui     $gp, $zero, 3
+# CHECK-NEXT:   20014:       8f 99 00 04     lw      $25, 4($gp)
+# CHECK-NEXT:   20018:       27 9c 00 04     addiu   $gp, $gp, 4
+# CHECK-NEXT:   2001c:       03 1c c0 23     subu    $24, $24, $gp
+# CHECK-NEXT:   20020:       03 e0 78 25     move    $15, $ra
+# CHECK-NEXT:   20024:       00 18 c0 82     srl     $24, $24, 2
+# CHECK-NEXT:   20028:       03 20 f8 09     jalr    $25
+# CHECK-NEXT:   2002c:       27 18 ff fe     addiu   $24, $24, -2
+
+# CHECK-NEXT:   20030:       3c 0f 00 03     aui     $15, $zero, 3
+# CHECK-NEXT:   20034:       8d f9 00 0c     lw      $25, 12($15)
+# CHECK-NEXT:   20038:       03 20 00 09     jr      $25
+# CHECK-NEXT:   2003c:       25 f8 00 0c     addiu   $24, $15, 12
+
+  .text
+  .global __start
+__start:
+  jal foo0        # R_MIPS_26 against 'foo0' from DSO
diff --git a/test/ELF/mips-reginfo.s b/test/ELF/mips-reginfo.s
new file mode 100644 (file)
index 0000000..4024a2f
--- /dev/null
@@ -0,0 +1,26 @@
+# Check MIPS .reginfo section generation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o --gc-sections -shared -o %t.so
+# RUN: llvm-readobj -symbols -mips-reginfo %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+    lw   $t0,%call16(g1)($gp)
+
+# CHECK:      Name: _gp
+# CHECK-NEXT: Value: 0x[[GP:[0-9A-F]+]]
+
+# CHECK:      MIPS RegInfo {
+# CHECK-NEXT:   GP: 0x[[GP]]
+# CHECK-NEXT:   General Mask: 0x10000101
+# CHECK-NEXT:   Co-Proc Mask0: 0x0
+# CHECK-NEXT:   Co-Proc Mask1: 0x0
+# CHECK-NEXT:   Co-Proc Mask2: 0x0
+# CHECK-NEXT:   Co-Proc Mask3: 0x0
+# CHECK-NEXT: }
diff --git a/test/ELF/mips-relocatable.s b/test/ELF/mips-relocatable.s
new file mode 100644 (file)
index 0000000..168ddf7
--- /dev/null
@@ -0,0 +1,21 @@
+# Check linking MIPS code in case of -r linker's option.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -r -o %t-r.o %t.o
+# RUN: llvm-objdump -s -t %t-r.o | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .global  __start
+__start:
+  lw      $t0,%call16(__start)($gp)
+foo:
+  nop
+
+  .section .rodata, "a"
+v:
+  .gpword foo
+
+# CHECK-NOT: Contents of section .got:
+# CHECK-NOT: {{.*}} _gp
diff --git a/test/ELF/mips-sto-pic-flag.s b/test/ELF/mips-sto-pic-flag.s
new file mode 100644 (file)
index 0000000..3960ba3
--- /dev/null
@@ -0,0 +1,58 @@
+# In case of linking PIC and non-PIC code together and generation
+# of a relocatable object, all PIC symbols should have STO_MIPS_PIC
+# flag in the symbol table of the ouput file.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:   %p/Inputs/mips-pic.s -o %t-pic.o
+# RUN: ld.lld -r %t-npic.o %t-pic.o -o %t-rel.o
+# RUN: llvm-readobj -t %t-rel.o | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Symbol {
+# CHECK:        Name: main
+# CHECK-NEXT:   Value:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Local
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: .text
+# CHECK-NEXT: }
+# CHECK:      Symbol {
+# CHECK:        Name: foo1a
+# CHECK-NEXT:   Value:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: Function
+# CHECK-NEXT:   Other [
+# CHECK-NEXT:     STO_MIPS_PIC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section: .text
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: foo1b
+# CHECK-NEXT:   Value:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: Function
+# CHECK-NEXT:   Other [
+# CHECK-NEXT:     STO_MIPS_PIC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section: .text
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT:   Name: foo2
+# CHECK-NEXT:   Value:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: Function
+# CHECK-NEXT:   Other [
+# CHECK-NEXT:     STO_MIPS_PIC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section: .text
+# CHECK-NEXT: }
+
+  .text
+main:
+  nop
diff --git a/test/ELF/mips-sto-plt.s b/test/ELF/mips-sto-plt.s
new file mode 100644 (file)
index 0000000..bd8de41
--- /dev/null
@@ -0,0 +1,66 @@
+# Check assigning STO_MIPS_PLT flag to symbol needs a pointer equality.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %S/Inputs/mips-dynamic.s -o %t.so.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -dt -mips-plt-got %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Symbol {
+# CHECK:        Name: foo0@
+# CHECK-NEXT:   Value: 0x0
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: Function
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Undefined
+# CHECK-NEXT: }
+# CHECK:      Symbol {
+# CHECK:        Name: foo1@
+# CHECK-NEXT:   Value: 0x20050
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Global
+# CHECK-NEXT:   Type: Function
+# CHECK-NEXT:   Other [ (0x8)
+# CHECK-NEXT:     STO_MIPS_PLT
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Section: Undefined
+# CHECK-NEXT: }
+
+# CHECK:      Primary GOT {
+# CHECK:        Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK:      PLT GOT {
+# CHECK:        Entries [
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Initial:
+# CHECK-NEXT:       Value: 0x0
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo0
+# CHECK-NEXT:     }
+# CHECK-NEXT:     Entry {
+# CHECK-NEXT:       Address:
+# CHECK-NEXT:       Initial:
+# CHECK-NEXT:       Value: 0x20050
+# CHECK-NEXT:       Type: Function
+# CHECK-NEXT:       Section: Undefined
+# CHECK-NEXT:       Name: foo1
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+
+  .text
+  .globl __start
+__start:
+  jal    foo0               # R_MIPS_26 against 'foo0' from DSO
+  lui    $t0,%hi(foo1)      # R_MIPS_HI16/LO16 against 'foo1' from DSO
+  addi   $t0,$t0,%lo(foo1)
+
+loc:
+  nop
diff --git a/test/ELF/mips-tls-64.s b/test/ELF/mips-tls-64.s
new file mode 100644 (file)
index 0000000..db29789
--- /dev/null
@@ -0,0 +1,111 @@
+# Check MIPS TLS 64-bit relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN:         %p/Inputs/mips-tls.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# RUN: ld.lld -shared %t.o %t.so -o %t-out.so
+# RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s
+# RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 80 20   addiu   $2, $3, -32736
+# DIS-NEXT:    20004:   24 62 80 30   addiu   $2, $3, -32720
+# DIS-NEXT:    20008:   24 62 80 38   addiu   $2, $3, -32712
+# DIS-NEXT:    2000c:   24 62 80 48   addiu   $2, $3, -32696
+# DIS-NEXT:    20010:   24 62 80 58   addiu   $2, $3, -32680
+
+# DIS:      Contents of section .got:
+# DIS-NEXT:  30010 00000000 00000000 80000000 00000000
+# DIS-NEXT:  30020 00000000 00000000 00000000 00000000
+# DIS-NEXT:  30030 00000000 00000000 00000000 00000001
+# DIS-NEXT:  30040 00000000 00000000 00000000 00000001
+# DIS-NEXT:  30050 ffffffff ffff8004 ffffffff ffff9004
+
+# DIS: 0000000000000000 l       .tdata          00000000 loc
+# DIS: 0000000000000004 g       .tdata          00000000 bar
+# DIS: 0000000000000000 g       *UND*           00000000 foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rela.dyn {
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:     0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:     0x30030 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value: 0x38000
+# CHECK-NEXT:   Reserved entries [
+# CHECK:        ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 8
+#               ^-- -32736 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 foo
+#               ^-- -32728                     R_MIPS_TLS_DTPREL64 foo
+#               ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  foo
+#               ^-- -32712 R_MIPS_TLS_LDM      1 loc
+#               ^-- -32704                     0 loc
+#               ^-- -32696 R_MIPS_TLS_GD       1 bar
+#               ^-- -32688                     VA - 0x8000 bar
+#               ^-- -32680 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+
+# DIS-SO:      Contents of section .got:
+# DIS-SO-NEXT:  20000 00000000 00000000 80000000 00000000
+# DIS-SO-NEXT:  20010 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20020 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20030 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20040 00000000 00000000 00000000 00000000
+
+# SO:      Relocations [
+# SO-NEXT:   Section (7) .rela.dyn {
+# SO-NEXT:     0x20028 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# SO-NEXT:     0x20038 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT:     0x20040 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT:     0x20048 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT:     0x20010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:     0x20020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT:   }
+# SO-NEXT: ]
+# SO-NEXT: Primary GOT {
+# SO-NEXT:   Canonical gp value: 0x27FF0
+# SO-NEXT:   Reserved entries [
+# SO:        ]
+# SO-NEXT:   Local entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Global entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Number of TLS and multi-GOT entries: 8
+#            ^-- -32736 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 foo
+#            ^-- -32728                     R_MIPS_TLS_DTPREL64 foo
+#            ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  foo
+#            ^-- -32712 R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD64 loc
+#            ^-- -32704                     0 loc
+#            ^-- -32696 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD64 bar
+#            ^-- -32688                     R_MIPS_TLS_DTPREL64 bar
+#            ^-- -32680 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64  bar
+
+  .text
+  .global  __start
+__start:
+  addiu $2, $3, %tlsgd(foo)     # R_MIPS_TLS_GD
+  addiu $2, $3, %gottprel(foo)  # R_MIPS_TLS_GOTTPREL
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  addiu $2, $3, %tlsgd(bar)     # R_MIPS_TLS_GD
+  addiu $2, $3, %gottprel(bar)  # R_MIPS_TLS_GOTTPREL
+
+ .section .tdata,"awT",%progbits
+ .global bar
+loc:
+ .word 0
+bar:
+ .word 0
diff --git a/test/ELF/mips-tls-hilo.s b/test/ELF/mips-tls-hilo.s
new file mode 100644 (file)
index 0000000..47fadaa
--- /dev/null
@@ -0,0 +1,51 @@
+# Check MIPS R_MIPS_TLS_DTPREL_HI16/LO16 and R_MIPS_TLS_TPREL_HI16/LO16
+# relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 00 00   addiu   $2, $3, 0
+#                       %hi(loc0 - .tdata - 0x8000) --^
+# DIS-NEXT:    20004:   24 62 80 00   addiu   $2, $3, -32768
+#                       %lo(loc0 - .tdata - 0x8000) --^
+# DIS-NEXT:    20008:   24 62 00 00   addiu   $2, $3, 0
+#                       %hi(loc0 - .tdata - 0x7000) --^
+# DIS-NEXT:    2000c:   24 62 90 00   addiu   $2, $3, -28672
+#                       %lo(loc0 - .tdata - 0x7000) --^
+
+# DIS: 00000000 l       .tdata          00000000 loc0
+
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+# CHECK-NOT:  Primary GOT
+
+# SO:      Relocations [
+# SO-NEXT: ]
+# SO:      Primary GOT {
+# SO:        Local entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Global entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Number of TLS and multi-GOT entries: 0
+# SO-NEXT: }
+
+  .text
+  .globl  __start
+  .type __start,@function
+__start:
+  addiu $2, $3, %dtprel_hi(loc0)  # R_MIPS_TLS_DTPREL_HI16
+  addiu $2, $3, %dtprel_lo(loc0)  # R_MIPS_TLS_DTPREL_LO16
+  addiu $2, $3, %tprel_hi(loc0)   # R_MIPS_TLS_TPREL_HI16
+  addiu $2, $3, %tprel_lo(loc0)   # R_MIPS_TLS_TPREL_LO16
+
+ .section .tdata,"awT",%progbits
+loc0:
+ .word 0
diff --git a/test/ELF/mips-tls-static-64.s b/test/ELF/mips-tls-static-64.s
new file mode 100644 (file)
index 0000000..6f88e86
--- /dev/null
@@ -0,0 +1,37 @@
+# Check handling TLS related relocations and symbols when linking
+# a 64-bit static executable.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t
+# RUN: ld.lld -static %t -o %t.exe
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Contents of section .data:
+# CHECK-NEXT:  30000 00020004 ffffffff ffff8004 ffffffff
+# CHECK-NEXT:  30010 ffff9004
+#
+# CHECK: SYMBOL TABLE:
+# CHECK: 0000000000020004         .text           00000000 __tls_get_addr
+# CHECK: 0000000000000000 g       .tdata          00000000 tls1
+
+  .text
+  .global __start
+__start:
+  nop
+
+  .global __tls_get_addr
+__tls_get_addr:
+  nop
+
+  .data
+loc:
+  .word __tls_get_addr
+  .dtpreldword tls1+4   # R_MIPS_TLS_DTPREL64
+  .tpreldword tls1+4    # R_MIPS_TLS_TPREL64
+
+ .section .tdata,"awT",%progbits
+ .global tls1
+tls1:
+ .word __tls_get_addr
+ .word 0
diff --git a/test/ELF/mips-tls-static.s b/test/ELF/mips-tls-static.s
new file mode 100644 (file)
index 0000000..84b56cb
--- /dev/null
@@ -0,0 +1,42 @@
+# Check handling TLS related relocations and symbols when linking
+# a static executable.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t
+# RUN: ld.lld -static %t -o %t.exe
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Contents of section .data:
+# CHECK-NEXT:  30000 0002000c ffff8004 ffff9004
+# CHECK:      Contents of section .got:
+# CHECK-NEXT:  30010 00000000 80000000 00000001 ffff8000
+# CHECK-NEXT:  30020 00000001 00000000 ffff9000
+#
+# CHECK: SYMBOL TABLE:
+# CHECK: 0002000c         .text           00000000 __tls_get_addr
+# CHECK: 00000000 g       .tdata          00000000 tls1
+
+  .text
+  .global __start
+__start:
+  addiu $2, $3, %tlsgd(tls1)      # R_MIPS_TLS_GD
+  addiu $2, $3, %tlsldm(tls2)     # R_MIPS_TLS_LDM
+  addiu $2, $3, %gottprel(tls1)   # R_MIPS_TLS_GOTTPREL
+
+  .global __tls_get_addr
+__tls_get_addr:
+  nop
+
+  .data
+loc:
+  .word __tls_get_addr
+  .dtprelword tls1+4    # R_MIPS_TLS_DTPREL32
+  .tprelword tls1+4     # R_MIPS_TLS_TPREL32
+
+ .section .tdata,"awT",%progbits
+ .global tls1
+tls1:
+ .word __tls_get_addr
+tls2:
+ .word 0
diff --git a/test/ELF/mips-tls.s b/test/ELF/mips-tls.s
new file mode 100644 (file)
index 0000000..b64f8db
--- /dev/null
@@ -0,0 +1,107 @@
+# Check MIPS TLS relocations handling.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN:         %p/Inputs/mips-tls.s -o %t.so.o
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s
+
+# RUN: ld.lld -shared %t.o %t.so -o %t-out.so
+# RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s
+# RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s
+
+# REQUIRES: mips
+
+# DIS:      __start:
+# DIS-NEXT:    20000:   24 62 80 18   addiu   $2, $3, -32744
+# DIS-NEXT:    20004:   24 62 80 20   addiu   $2, $3, -32736
+# DIS-NEXT:    20008:   24 62 80 24   addiu   $2, $3, -32732
+# DIS-NEXT:    2000c:   24 62 80 2c   addiu   $2, $3, -32724
+# DIS-NEXT:    20010:   24 62 80 34   addiu   $2, $3, -32716
+
+# DIS:      Contents of section .got:
+# DIS-NEXT:  30010 00000000 80000000 00000000 00000000
+# DIS-NEXT:  30020 00000000 00000001 00000000 00000001
+# DIS-NEXT:  30030 ffff8004 ffff9004
+
+# DIS: 00000000 l       .tdata          00000000 loc
+# DIS: 00000004 g       .tdata          00000000 bar
+# DIS: 00000000 g       *UND*           00000000 foo
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section (7) .rel.dyn {
+# CHECK-NEXT:     0x30018 R_MIPS_TLS_DTPMOD32 foo 0x0
+# CHECK-NEXT:     0x3001C R_MIPS_TLS_DTPREL32 foo 0x0
+# CHECK-NEXT:     0x30020 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Primary GOT {
+# CHECK-NEXT:   Canonical gp value: 0x38000
+# CHECK-NEXT:   Reserved entries [
+# CHECK:        ]
+# CHECK-NEXT:   Local entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Global entries [
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Number of TLS and multi-GOT entries: 8
+#               ^-- -32744 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
+#               ^-- -32740                     R_MIPS_TLS_DTPREL32 foo
+#               ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
+#               ^-- -32732 R_MIPS_TLS_LDM      1 loc
+#               ^-- -32728                     0 loc
+#               ^-- -32724 R_MIPS_TLS_GD       1 bar
+#               ^-- -32720                     VA - 0x8000 bar
+#               ^-- -32716 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+
+# DIS-SO:      Contents of section .got:
+# DIS-SO-NEXT:  20000 00000000 80000000 00000000 00000000
+# DIS-SO-NEXT:  20010 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT:  20020 00000000 00000000
+
+# SO:      Relocations [
+# SO-NEXT:   Section (7) .rel.dyn {
+# SO-NEXT:     0x20014 R_MIPS_TLS_DTPMOD32 - 0x0
+# SO-NEXT:     0x2001C R_MIPS_TLS_DTPMOD32 bar 0x0
+# SO-NEXT:     0x20020 R_MIPS_TLS_DTPREL32 bar 0x0
+# SO-NEXT:     0x20024 R_MIPS_TLS_TPREL32 bar 0x0
+# SO-NEXT:     0x20008 R_MIPS_TLS_DTPMOD32 foo 0x0
+# SO-NEXT:     0x2000C R_MIPS_TLS_DTPREL32 foo 0x0
+# SO-NEXT:     0x20010 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT:   }
+# SO-NEXT: ]
+# SO-NEXT: Primary GOT {
+# SO-NEXT:   Canonical gp value: 0x27FF0
+# SO-NEXT:   Reserved entries [
+# SO:        ]
+# SO-NEXT:   Local entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Global entries [
+# SO-NEXT:   ]
+# SO-NEXT:   Number of TLS and multi-GOT entries: 8
+#            ^-- -32744 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 foo
+#            ^-- -32740 R_MIPS_TLS_DTPREL32 foo
+#            ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  foo
+#            ^-- -32732 R_MIPS_TLS_LDM      R_MIPS_TLS_DTPMOD32 loc
+#            ^-- -32728 0 loc
+#            ^-- -32724 R_MIPS_TLS_GD       R_MIPS_TLS_DTPMOD32 bar
+#            ^-- -32720 R_MIPS_TLS_DTPREL32 bar
+#            ^-- -32716 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32  bar
+
+  .text
+  .global  __start
+__start:
+  addiu $2, $3, %tlsgd(foo)     # R_MIPS_TLS_GD
+  addiu $2, $3, %gottprel(foo)  # R_MIPS_TLS_GOTTPREL
+  addiu $2, $3, %tlsldm(loc)    # R_MIPS_TLS_LDM
+  addiu $2, $3, %tlsgd(bar)     # R_MIPS_TLS_GD
+  addiu $2, $3, %gottprel(bar)  # R_MIPS_TLS_GOTTPREL
+
+ .section .tdata,"awT",%progbits
+ .global bar
+loc:
+ .word 0
+bar:
+ .word 0
diff --git a/test/ELF/mips-xgot-order.s b/test/ELF/mips-xgot-order.s
new file mode 100644 (file)
index 0000000..911731c
--- /dev/null
@@ -0,0 +1,49 @@
+# Check that GOT entries accessed via 16-bit indexing are allocated
+# in the beginning of the GOT.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    20004:       8c 42 80 24     lw      $2, -32732($2)
+# CHECK-NEXT:    20008:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    2000c:       8c 42 80 28     lw      $2, -32728($2)
+#
+# CHECK:      bar:
+# CHECK-NEXT:    20010:       8c 42 80 20     lw      $2, -32736($2)
+# CHECK-NEXT:    20014:       8c 42 80 18     lw      $2, -32744($2)
+# CHECK-NEXT:    20018:       20 42 00 00     addi    $2, $2, 0
+
+# CHECK:      Contents of section .got:
+# CHECK-NEXT:  30010 00000000 80000000 00030000 00040000
+#                                      ^ %hi(loc)
+#                                               ^ redundant entry
+# CHECK-NEXT:  30020 00020010 00020000 00030000
+#                    ^ %got(bar)
+#                             ^ %got_hi/lo(start)
+#                                      ^ %got_hi/lo(loc)
+
+# CHECK: 00030000         .data           00000000 loc
+# CHECK: 00020000         .text           00000000 __start
+# CHECK: 00020010         .text           00000000 bar
+
+  .text
+  .global __start, bar
+__start:
+  lui   $2, %got_hi(__start)
+  lw    $2, %got_lo(__start)($2)
+  lui   $2, %got_hi(loc)
+  lw    $2, %got_lo(loc)($2)
+bar:
+  lw    $2, %got(bar)($2)
+  lw    $2, %got(loc)($2)
+  addi  $2, $2, %lo(loc)
+
+  .data
+loc:
+  .word 0
diff --git a/test/ELF/mips64-eh-abs-reloc.s b/test/ELF/mips64-eh-abs-reloc.s
new file mode 100644 (file)
index 0000000..7bc5001
--- /dev/null
@@ -0,0 +1,38 @@
+# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD
+# REQUIRES: mips
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
+# RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ
+# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o
+# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix PIC-RELOCS
+
+# Linking this as a PIE executable would also previously crash
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %S/Inputs/archive2.s -o %t-foo.o
+# -pie needs -z notext because of the R_MIPS_64 relocation
+# RUN: ld.lld --eh-frame-hdr -Bdynamic -pie -z notext -o %t-pie-dynamic.exe %t.o %t-foo.o
+# RUN: llvm-readobj -r %t-pie-dynamic.exe | FileCheck %s -check-prefix PIC-RELOCS
+
+
+# OBJ:       Section ({{.*}}) .rela.text {
+# OBJ-NEXT:    0x0 R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 foo 0x0
+# OBJ-NEXT:  }
+# OBJ-NEXT:  Section ({{.*}}) .rela.eh_frame {
+# OBJ-NEXT:    0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0
+# OBJ-NEXT:  }
+
+# PIC-RELOCS: Relocations [
+# PIC-RELOCS-NEXT:  Section (7) .rela.dyn {
+# PIC-RELOCS-NEXT:    {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x10000
+# PIC-RELOCS-NEXT:  }
+# PIC-RELOCS-NEXT:]
+
+
+.globl foo
+
+bar:
+.cfi_startproc
+lui    $11, %hi(%neg(%gp_rel(foo)))
+.cfi_endproc
+
+.globl __start
+__start:
+b bar
diff --git a/test/ELF/new-dtags.test b/test/ELF/new-dtags.test
new file mode 100644 (file)
index 0000000..1ae328c
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -rpath=/somepath -shared --disable-new-dtags -o %t
+// RUN: ld.lld %t.o -rpath=/somepath -shared --enable-new-dtags -o %t2
+// RUN: llvm-readobj --dynamic-table %t | FileCheck --check-prefix=DISABLE %s
+// RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=ENABLE %s
+
+// DISABLE: DynamicSection [
+// DISABLE:   0x000000000000000F RPATH                /somepath
+// DISABLE-NOT: RUNPATH
+// DISABLE: ]
+
+// ENABLE: DynamicSection [
+// ENABLE:   0x000000000000001D RUNPATH              /somepath
+// ENABLE-NOT: RPATH
+// ENABLE: ]
diff --git a/test/ELF/no-augmentation.s b/test/ELF/no-augmentation.s
new file mode 100644 (file)
index 0000000..31cd92e
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
+// RUN: ld.lld --eh-frame-hdr %t.o -o %t | FileCheck -allow-empty %s
+
+// REQUIRES: mips
+
+// CHECK-NOT: corrupted or unsupported CIE information
+// CHECK-NOT: corrupted CIE
+
+.global __start
+__start:
+
+.section        .eh_frame,"aw",@progbits
+        .4byte  9
+        .4byte  0x0
+        .byte   0x1
+        .string ""
+        .uleb128 0x1
+        .sleb128 -4
+        .byte   0x1f
diff --git a/test/ELF/no-dynamic-linker.s b/test/ELF/no-dynamic-linker.s
new file mode 100644 (file)
index 0000000..f5c7f4b
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %tso.o
+# RUN: ld.lld -shared %tso.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: ld.lld -dynamic-linker foo --no-dynamic-linker %t.o %t.so -o %t
+# RUN: llvm-readobj --program-headers %t | FileCheck %s --check-prefix=NODL
+# NODL-NOT: PT_INTERP
+
+# RUN: ld.lld --no-dynamic-linker -dynamic-linker foo %t.o %t.so -o %t
+# RUN: llvm-readobj --program-headers %t | FileCheck %s --check-prefix=WITHDL
+# WITHDL: PT_INTERP
diff --git a/test/ELF/no-inhibit-exec.s b/test/ELF/no-inhibit-exec.s
new file mode 100644 (file)
index 0000000..d0970d9
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t -o %t2
+# RUN: ld.lld %t --noinhibit-exec -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: x86
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: _start
+# CHECK-NEXT: 201000: {{.*}} callq -2101253
+
+# next code will not link without noinhibit-exec flag
+# because of undefined symbol _bar
+.globl _start
+_start:
+  call _bar
diff --git a/test/ELF/no-merge.s b/test/ELF/no-merge.s
new file mode 100644 (file)
index 0000000..c8132c2
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .rodata : {*(.rodata.*)} }" > %t0.script
+# RUN: ld.lld %t.o -o %t0.out --script %t0.script
+# RUN: llvm-objdump -s %t0.out | FileCheck %s
+
+# RUN: ld.lld -O0 %t.o -o %t1.out --script %t0.script
+# RUN: llvm-objdump -s %t1.out | FileCheck %s
+# CHECK:      Contents of section .rodata:
+# CHECK-NEXT:   0000 01610003
+
+.section .rodata.a,"a",@progbits
+.byte 1
+
+.section .rodata.ams,"aMS",@progbits,1
+.asciz "a"
+
+.section .rodata.am,"aM",@progbits,1
+.byte 3
diff --git a/test/ELF/no-obj.s b/test/ELF/no-obj.s
new file mode 100644 (file)
index 0000000..693cdf1
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-ar rcs %t.a %t.o
+// RUN: not ld.lld -o %t2 -u _start %t.a 2>&1 | FileCheck %s
+
+// CHECK: target emulation unknown: -m or at least one .o file required
+
+.global _start
+_start:
diff --git a/test/ELF/no-plt-shared.s b/test/ELF/no-plt-shared.s
new file mode 100644 (file)
index 0000000..ac45ed5
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.so -o %t2.so -shared
+// RUN: llvm-readobj -r %t2.so | FileCheck %s
+
+        .data
+fp:
+        .quad bar
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     R_X86_64_64 bar 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/no-soname.s b/test/ELF/no-soname.s
new file mode 100644 (file)
index 0000000..e3869ff
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: mkdir -p %T/no-soname
+// RUN: ld.lld %t.o -shared -o %T/no-soname/libfoo.so
+
+// RUN: ld.lld %t.o %T/no-soname/libfoo.so -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s
+
+// CHECK:  0x0000000000000001 NEEDED               Shared library: [{{.*}}/no-soname/libfoo.so]
+// CHECK-NOT: NEEDED
+
+// RUN: ld.lld %t.o %T/no-soname/../no-soname/libfoo.so -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s --check-prefix=CHECK2
+
+// CHECK2:  0x0000000000000001 NEEDED               Shared library: [{{.*}}/no-soname/../no-soname/libfoo.so]
+// CHECK2-NOT: NEEDED
+
+// RUN: ld.lld %t.o -L%T/no-soname/../no-soname -lfoo -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s --check-prefix=CHECK3
+
+// CHECK3:  0x0000000000000001 NEEDED               Shared library: [libfoo.so]
+// CHECK3-NOT: NEEDED
+
+// RUN: ld.lld %t.o -shared -soname libbar.so -o %T/no-soname/libbar.so
+// RUN: ld.lld %t.o %T/no-soname/libbar.so -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s --check-prefix=CHECK4
+
+// CHECK4:  0x0000000000000001 NEEDED               Shared library: [libbar.so]
+// CHECK4-NOT: NEEDED
+
+.global _start
+_start:
diff --git a/test/ELF/no-symtab.s b/test/ELF/no-symtab.s
new file mode 100644 (file)
index 0000000..af9df13
--- /dev/null
@@ -0,0 +1,5 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o %p/Inputs/no-symtab.o -o %t
+.global _start
+_start:
diff --git a/test/ELF/no-undefined.s b/test/ELF/no-undefined.s
new file mode 100644 (file)
index 0000000..493a389
--- /dev/null
@@ -0,0 +1,8 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld --no-undefined -shared %t -o %t.so
+# RUN: ld.lld -shared %t -o %t1.so
+
+.globl _shared
+_shared:
+  callq _unresolved@PLT
diff --git a/test/ELF/non-abs-reloc.s b/test/ELF/non-abs-reloc.s
new file mode 100644 (file)
index 0000000..ef9ba44
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+// CHECK: {{.*}}:(.dummy+0x0): has non-ABS reloc
+
+.globl _start
+_start:
+  nop
+
+.section .dummy
+  .long foo@gotpcrel
diff --git a/test/ELF/noplt-pie.s b/test/ELF/noplt-pie.s
new file mode 100644 (file)
index 0000000..81e4410
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: ld.lld %t1.o %t2.so -o %t.out
+# RUN: llvm-readobj -s -r %t.out | FileCheck %s
+
+# CHECK: Section {
+# CHECK-NOT: Name: .plt
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x2020B0 R_X86_64_GLOB_DAT bar 0x0
+# CHECK-NEXT:     0x2020B8 R_X86_64_GLOB_DAT zed 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+ movq bar@GOTPCREL(%rip), %rcx
+ movq zed@GOTPCREL(%rip), %rcx
diff --git a/test/ELF/note-contiguous.s b/test/ELF/note-contiguous.s
new file mode 100644 (file)
index 0000000..f49d0b6
--- /dev/null
@@ -0,0 +1,24 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: echo "SECTIONS { \
+// RUN:  .note : { *(.note.a) *(.note.b) } \
+// RUN: }" > %t.script
+// RUN: ld.lld %t.o --script %t.script -o %t
+// RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+// CHECK:      Type: PT_NOTE
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: VirtualAddress: 0x0
+// CHECK-NEXT: PhysicalAddress: 0x0
+// CHECK-NEXT: FileSize: 16
+// CHECK-NEXT: MemSize: 16
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+
+.section .note.a, "a", @note
+.quad 0
+
+.section .note.b, "a", @note
+.quad 0
diff --git a/test/ELF/note-loadaddr.c b/test/ELF/note-loadaddr.c
new file mode 100644 (file)
index 0000000..6d2ebae
--- /dev/null
@@ -0,0 +1,35 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: echo "SECTIONS { \
+// RUN:  .note.a : AT(0x1000) { *(.note.a) } \
+// RUN:  .note.b : AT(0x2000) { *(.note.b) } \
+// RUN: }" > %t.script
+// RUN: ld.lld %t.o --script %t.script -o %t
+// RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+// CHECK:      Type: PT_NOTE
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: VirtualAddress: 0x0
+// CHECK-NEXT: PhysicalAddress: 0x1000
+// CHECK-NEXT: FileSize: 8
+// CHECK-NEXT: MemSize: 8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+// CHECK:      Type: PT_NOTE
+// CHECK-NEXT: Offset: 0x1008
+// CHECK-NEXT: VirtualAddress: 0x8
+// CHECK-NEXT: PhysicalAddress: 0x2000
+// CHECK-NEXT: FileSize: 8
+// CHECK-NEXT: MemSize: 8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+
+.section .note.a, "a", @note
+.quad 0
+
+.section .note.b, "a", @note
+.quad 0
diff --git a/test/ELF/note-multiple.s b/test/ELF/note-multiple.s
new file mode 100644 (file)
index 0000000..cebe8aa
--- /dev/null
@@ -0,0 +1,43 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: echo "SECTIONS { \
+// RUN:  .note.a : { *(.note.a) } \
+// RUN:  .b : { *(.b) } \
+// RUN:  .c : { *(.c) } \
+// RUN:  .note.d : { *(.note.d) } \
+// RUN: }" > %t.script
+// RUN: ld.lld %t.o --script %t.script -o %t
+// RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+// CHECK:      Type: PT_NOTE
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: VirtualAddress: 0x0
+// CHECK-NEXT: PhysicalAddress: 0x0
+// CHECK-NEXT: FileSize: 8
+// CHECK-NEXT: MemSize: 8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+// CHECK:      Type: PT_NOTE
+// CHECK-NEXT: Offset: 0x1018
+// CHECK-NEXT: VirtualAddress: 0x18
+// CHECK-NEXT: PhysicalAddress: 0x18
+// CHECK-NEXT: FileSize: 8
+// CHECK-NEXT: MemSize: 8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+
+.section .note.a, "a", @note
+.quad 0
+
+.section .b, "a"
+.quad 0
+
+.section .c, "a"
+.quad 0
+
+.section .note.d, "a", @note
+.quad 0
diff --git a/test/ELF/note.s b/test/ELF/note.s
new file mode 100644 (file)
index 0000000..a383b95
--- /dev/null
@@ -0,0 +1,18 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -program-headers %t | FileCheck %s
+
+// CHECK:      Type: PT_NOTE
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: VirtualAddress:
+// CHECK-NEXT: PhysicalAddress:
+// CHECK-NEXT: FileSize:        8
+// CHECK-NEXT: MemSize:         8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment:       1
+
+        .section        .note.test,"a",@note
+        .quad 42
diff --git a/test/ELF/oformat-binary-ttext.s b/test/ELF/oformat-binary-ttext.s
new file mode 100644 (file)
index 0000000..aced1a3
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld -N -Ttext 0x100 -o %t.out %t --oformat binary
+# RUN: od -t x1 -v %t.out | FileCheck %s --check-prefix=BIN
+
+# BIN:      0000000 90 00 00 00 00 00 00 00
+# BIN-NEXT: 0000010
+# BIN-NOT:  0000020
+
+## The same but without OMAGIC.
+# RUN: ld.lld -Ttext 0x100 -o %t.out %t --oformat binary
+# RUN: od -t x1 -v %t.out | FileCheck %s --check-prefix=BIN
+
+.text
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/oformat-binary.s b/test/ELF/oformat-binary.s
new file mode 100644 (file)
index 0000000..acd95c7
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: ld.lld -o %t.out %t --oformat binary
+# RUN: od -t x1 -v %t.out | FileCheck %s
+# CHECK: 000000 90 11 22 00 00 00 00 00
+# CHECK-NOT: 00000010
+
+## Check case when linkerscript is used.
+# RUN: echo "SECTIONS { . = 0x1000; }" > %t.script
+# RUN: ld.lld -o %t2.out --script %t.script %t --oformat binary
+# RUN: od -t x1 -v %t2.out | FileCheck %s
+
+# RUN: echo "SECTIONS { }" > %t.script
+# RUN: ld.lld -o %t2.out --script %t.script %t --oformat binary
+# RUN: od -t x1 -v %t2.out | FileCheck %s
+
+# RUN: not ld.lld -o %t3.out %t --oformat foo 2>&1 \
+# RUN:   | FileCheck %s --check-prefix ERR
+# ERR: unknown --oformat value: foo
+
+.text
+.align 4
+.globl _start
+_start:
+ nop
+
+.section        .mysec.1,"ax"
+.byte   0x11
+
+.section        .mysec.2,"ax"
+.byte   0x22
diff --git a/test/ELF/openbsd-randomize.s b/test/ELF/openbsd-randomize.s
new file mode 100644 (file)
index 0000000..794e87b
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld %t -o %t.out
+# RUN: llvm-readobj --program-headers %t.out | FileCheck %s
+
+# CHECK:      ProgramHeader {
+# CHECK:        Type: PT_OPENBSD_RANDOMIZE (0x65A3DBE6)
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   VirtualAddress:
+# CHECK-NEXT:   PhysicalAddress:
+# CHECK-NEXT:   FileSize: 8
+# CHECK-NEXT:   MemSize: 8
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     PF_R (0x4)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Alignment: 1
+# CHECK-NEXT: }
+
+.section .openbsd.randomdata, "a"
+.quad 0
diff --git a/test/ELF/openbsd-wxneeded.s b/test/ELF/openbsd-wxneeded.s
new file mode 100644 (file)
index 0000000..d209e4f
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld -z wxneeded %t -o %t.out
+# RUN: llvm-readobj --program-headers %t.out | FileCheck %s
+
+# CHECK:      ProgramHeader {
+# CHECK:        Type: PT_OPENBSD_WXNEEDED (0x65A3DBE7)
+# CHECK-NEXT:   Offset: 0x0
+# CHECK-NEXT:   VirtualAddress: 0x0
+# CHECK-NEXT:   PhysicalAddress: 0x0
+# CHECK-NEXT:   FileSize: 0
+# CHECK-NEXT:   MemSize: 0
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     PF_X
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Alignment: 0
+# CHECK-NEXT: }
diff --git a/test/ELF/output-section.s b/test/ELF/output-section.s
new file mode 100644 (file)
index 0000000..6850525
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Symbol {
+// CHECK:        Name: bar_sym
+// CHECK-NEXT:   Value:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Binding:
+// CHECK-NEXT:   Type:
+// CHECK-NEXT:   Other:
+// CHECK-NEXT:   Section: bar
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: foo_sym
+// CHECK-NEXT:   Value:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Binding:
+// CHECK-NEXT:   Type:
+// CHECK-NEXT:   Other:
+// CHECK-NEXT:   Section: foo
+// CHECK-NEXT: }
+
+.section foo
+.global foo_sym
+foo_sym:
+
+.section bar, "a"
+.global bar_sym
+bar_sym:
+
+.global _start
+_start:
diff --git a/test/ELF/phdr-align.s b/test/ELF/phdr-align.s
new file mode 100644 (file)
index 0000000..354897e
--- /dev/null
@@ -0,0 +1,83 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN:  . = SIZEOF_HEADERS; \
+# RUN:  .bss : { *(.bss) } \
+# RUN:  .data : { *(.data) } \
+# RUN:  .text : { *(.text) } }" > %t.script
+# RUN: ld.lld %t.o --script %t.script -o %t
+# RUN: llvm-readobj -sections -symbols %t | FileCheck %s
+
+# CHECK:      Sections [
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 0
+# CHECK-NEXT:    Name:  (0)
+# CHECK-NEXT:    Type: SHT_NULL
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x0
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    Size: 0
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 0
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 1
+# CHECK-NEXT:    Name: .bss
+# CHECK-NEXT:    Type: SHT_NOBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x158
+# CHECK-NEXT:    Offset: 0x158
+# CHECK-NEXT:    Size: 6
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 2
+# CHECK-NEXT:    Name: .data
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_WRITE
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x15E
+# CHECK-NEXT:    Offset: 0x15E
+# CHECK-NEXT:    Size: 2
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 1
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Section {
+# CHECK-NEXT:    Index: 3
+# CHECK-NEXT:    Name: .text
+# CHECK-NEXT:    Type: SHT_PROGBITS
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      SHF_ALLOC
+# CHECK-NEXT:      SHF_EXECINSTR
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x160
+# CHECK-NEXT:    Offset: 0x160
+# CHECK-NEXT:    Size: 1
+# CHECK-NEXT:    Link: 0
+# CHECK-NEXT:    Info: 0
+# CHECK-NEXT:    AddressAlignment: 4
+# CHECK-NEXT:    EntrySize: 0
+# CHECK-NEXT:  }
+
+.global _start
+.text
+_start:
+ nop
+.data
+ .word 1
+.bss
+ .space 6
diff --git a/test/ELF/pie-weak.s b/test/ELF/pie-weak.s
new file mode 100644 (file)
index 0000000..99dbd47
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -relax-relocations=false -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOCS %s
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+# RELOCS:      Relocations [
+# RELOCS-NEXT: ]
+
+.weak foo
+
+.globl _start
+_start:
+# DISASM: _start:
+# DISASM-NEXT: 1000: 48 8b 05 69 10 00 00 movq 4201(%rip), %rax
+#                                              ^ .got - (.text + 7)
+mov foo@gotpcrel(%rip), %rax
diff --git a/test/ELF/pie.s b/test/ELF/pie.s
new file mode 100644 (file)
index 0000000..5964db5
--- /dev/null
@@ -0,0 +1,56 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+## Default is no PIE.
+# RUN: ld.lld %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t \
+# RUN:   | FileCheck %s --check-prefix=NOPIE
+
+## Check -pie.
+# RUN: ld.lld -pie %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+## Test --pic-executable alias
+# RUN: ld.lld --pic-executable %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:  Ident {
+# CHECK-NEXT:    Magic: (7F 45 4C 46)
+# CHECK-NEXT:    Class: 64-bit
+# CHECK-NEXT:    DataEncoding: LittleEndian
+# CHECK-NEXT:    FileVersion: 1
+# CHECK-NEXT:    OS/ABI: SystemV
+# CHECK-NEXT:    ABIVersion: 0
+# CHECK-NEXT:    Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Type: SharedObject
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_PHDR
+# CHECK-NEXT:    Offset: 0x40
+# CHECK-NEXT:    VirtualAddress: 0x40
+# CHECK-NEXT:    PhysicalAddress: 0x40
+# CHECK-NEXT:    FileSize:
+# CHECK-NEXT:    MemSize:
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 8
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+
+# CHECK:         Type: PT_DYNAMIC
+
+## Check -nopie
+# RUN: ld.lld -nopie %t1.o -o %t2
+# RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE
+# NOPIE-NOT: Type: SharedObject
+
+.globl _start
+_start:
diff --git a/test/ELF/plt-aarch64.s b/test/ELF/plt-aarch64.s
new file mode 100644 (file)
index 0000000..372186b
--- /dev/null
@@ -0,0 +1,203 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/plt-aarch64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -shared %t.o %t2.so -o %t.so
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -s -r %t.so | FileCheck --check-prefix=CHECKDSO %s
+// RUN: llvm-objdump -s -section=.got.plt %t.so | FileCheck --check-prefix=DUMPDSO %s
+// RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASMDSO %s
+// RUN: llvm-readobj -s -r %t.exe | FileCheck --check-prefix=CHECKEXE %s
+// RUN: llvm-objdump -s -section=.got.plt %t.exe | FileCheck --check-prefix=DUMPEXE %s
+// RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASMEXE %s
+
+// REQUIRES: aarch64
+
+// CHECKDSO:     Name: .plt
+// CHECKDSO-NEXT:     Type: SHT_PROGBITS
+// CHECKDSO-NEXT:     Flags [
+// CHECKDSO-NEXT:       SHF_ALLOC
+// CHECKDSO-NEXT:       SHF_EXECINSTR
+// CHECKDSO-NEXT:     ]
+// CHECKDSO-NEXT:     Address: 0x10010
+// CHECKDSO-NEXT:     Offset:
+// CHECKDSO-NEXT:     Size: 80
+// CHECKDSO-NEXT:     Link:
+// CHECKDSO-NEXT:     Info:
+// CHECKDSO-NEXT:     AddressAlignment: 16
+
+// CHECKDSO:     Name: .got.plt
+// CHECKDSO-NEXT:     Type: SHT_PROGBITS
+// CHECKDSO-NEXT:     Flags [
+// CHECKDSO-NEXT:       SHF_ALLOC
+// CHECKDSO-NEXT:       SHF_WRITE
+// CHECKDSO-NEXT:     ]
+// CHECKDSO-NEXT:     Address: 0x20000
+// CHECKDSO-NEXT:     Offset:
+// CHECKDSO-NEXT:     Size: 48
+// CHECKDSO-NEXT:     Link:
+// CHECKDSO-NEXT:     Info:
+// CHECKDSO-NEXT:     AddressAlignment: 8
+
+// CHECKDSO: Relocations [
+// CHECKDSO-NEXT:   Section ({{.*}}) .rela.plt {
+
+// &(.got.plt[3]) = 0x20000 + 3 * 8 = 0x30018
+// CHECKDSO-NEXT:     0x20018 R_AARCH64_JUMP_SLOT foo
+
+// &(.got.plt[4]) = 0x20000 + 4 * 8 = 0x30020
+// CHECKDSO-NEXT:     0x20020 R_AARCH64_JUMP_SLOT bar
+
+// &(.got.plt[5]) = 0x20000 + 5 * 8 = 0x30028
+// CHECKDSO-NEXT:     0x20028 R_AARCH64_JUMP_SLOT weak
+// CHECKDSO-NEXT:   }
+// CHECKDSO-NEXT: ]
+
+// DUMPDSO: Contents of section .got.plt:
+// .got.plt[0..2] = 0 (reserved)
+// .got.plt[3..5] = .plt = 0x10010
+// DUMPDSO-NEXT: 20000 00000000 00000000 00000000 00000000  ................
+// DUMPDSO-NEXT: 20010 00000000 00000000 10000100 00000000  ................
+// DUMPDSO-NEXT: 20020 10000100 00000000 10000100 00000000  ................
+
+// DISASMDSO: _start:
+// 0x10030 - 0x10000 = 0x30 = 48
+// DISASMDSO-NEXT:     10000:  0c 00 00 14     b       #48
+// 0x10040 - 0x10004 = 0x3c = 60
+// DISASMDSO-NEXT:     10004:  0f 00 00 14     b       #60
+// 0x10050 - 0x10008 = 0x48 = 72
+// DISASMDSO-NEXT:     10008:  12 00 00 14     b       #72
+
+// DISASMDSO: foo:
+// DISASMDSO-NEXT:     1000c:  1f 20 03 d5     nop
+
+// DISASMDSO: Disassembly of section .plt:
+// DISASMDSO-NEXT: .plt:
+// DISASMDSO-NEXT:     10010:  f0 7b bf a9     stp     x16, x30, [sp, #-16]!
+// &(.got.plt[2]) = 0x3000 + 2 * 8 = 0x3010
+// Page(0x20010) - Page(0x10014) = 0x20000 - 0x10000 = 0x10000 = 65536
+// DISASMDSO-NEXT:     10014:  90 00 00 90     adrp    x16, #65536
+// 0x3010 & 0xFFF = 0x10 = 16
+// DISASMDSO-NEXT:     10018:  11 0a 40 f9 ldr x17, [x16, #16]
+// DISASMDSO-NEXT:     1001c:  10 42 00 91     add     x16, x16, #16
+// DISASMDSO-NEXT:     10020:  20 02 1f d6     br      x17
+// DISASMDSO-NEXT:     10024:  1f 20 03 d5     nop
+// DISASMDSO-NEXT:     10028:  1f 20 03 d5     nop
+// DISASMDSO-NEXT:     1002c:  1f 20 03 d5     nop
+
+// foo@plt
+// Page(0x30018) - Page(0x10030) = 0x20000 - 0x10000 = 0x10000 = 65536
+// DISASMDSO-NEXT:     10030:  90 00 00 90     adrp    x16, #65536
+// 0x3018 & 0xFFF = 0x18 = 24
+// DISASMDSO-NEXT:     10034:  11 0e 40 f9     ldr     x17, [x16, #24]
+// DISASMDSO-NEXT:     10038:  10 62 00 91     add     x16, x16, #24
+// DISASMDSO-NEXT:     1003c:  20 02 1f d6     br      x17
+
+// bar@plt
+// Page(0x30020) - Page(0x10040) = 0x20000 - 0x10000 = 0x10000 = 65536
+// DISASMDSO-NEXT:     10040:  90 00 00 90     adrp    x16, #65536
+// 0x3020 & 0xFFF = 0x20 = 32
+// DISASMDSO-NEXT:     10044:  11 12 40 f9     ldr     x17, [x16, #32]
+// DISASMDSO-NEXT:     10048:  10 82 00 91     add     x16, x16, #32
+// DISASMDSO-NEXT:     1004c:  20 02 1f d6     br      x17
+
+// weak@plt
+// Page(0x30028) - Page(0x10050) = 0x20000 - 0x10000 = 0x10000 = 65536
+// DISASMDSO-NEXT:     10050:  90 00 00 90     adrp    x16, #65536
+// 0x3028 & 0xFFF = 0x28 = 40
+// DISASMDSO-NEXT:     10054:  11 16 40 f9     ldr     x17, [x16, #40]
+// DISASMDSO-NEXT:     10058:  10 a2 00 91     add     x16, x16, #40
+// DISASMDSO-NEXT:     1005c:  20 02 1f d6     br      x17
+
+// CHECKEXE:     Name: .plt
+// CHECKEXE-NEXT:     Type: SHT_PROGBITS
+// CHECKEXE-NEXT:     Flags [
+// CHECKEXE-NEXT:       SHF_ALLOC
+// CHECKEXE-NEXT:       SHF_EXECINSTR
+// CHECKEXE-NEXT:     ]
+// CHECKEXE-NEXT:     Address: 0x20010
+// CHECKEXE-NEXT:     Offset:
+// CHECKEXE-NEXT:     Size: 64
+// CHECKEXE-NEXT:     Link:
+// CHECKEXE-NEXT:     Info:
+// CHECKEXE-NEXT:     AddressAlignment: 16
+
+// CHECKEXE:     Name: .got.plt
+// CHECKEXE-NEXT:     Type: SHT_PROGBITS
+// CHECKEXE-NEXT:     Flags [
+// CHECKEXE-NEXT:       SHF_ALLOC
+// CHECKEXE-NEXT:       SHF_WRITE
+// CHECKEXE-NEXT:     ]
+// CHECKEXE-NEXT:     Address: 0x30000
+// CHECKEXE-NEXT:     Offset:
+// CHECKEXE-NEXT:     Size: 40
+// CHECKEXE-NEXT:     Link:
+// CHECKEXE-NEXT:     Info:
+// CHECKEXE-NEXT:     AddressAlignment: 8
+
+// CHECKEXE: Relocations [
+// CHECKEXE-NEXT:   Section ({{.*}}) .rela.plt {
+
+// &(.got.plt[3]) = 0x30000 + 3 * 8 = 0x30018
+// CHECKEXE-NEXT:     0x30018 R_AARCH64_JUMP_SLOT bar 0x0
+
+// &(.got.plt[4]) = 0x30000 + 4 * 8 = 0x30020
+// CHECKEXE-NEXT:     0x30020 R_AARCH64_JUMP_SLOT weak 0x0
+// CHECKEXE-NEXT:   }
+// CHECKEXE-NEXT: ]
+
+// DUMPEXE: Contents of section .got.plt:
+// .got.plt[0..2] = 0 (reserved)
+// .got.plt[3..4] = .plt = 0x40010
+// DUMPEXE-NEXT:  30000 00000000 00000000 00000000 00000000  ................
+// DUMPEXE-NEXT:  30010 00000000 00000000 10000200 00000000  ................
+// DUMPEXE-NEXT:  30020 10000200 00000000                    ........
+
+// DISASMEXE: _start:
+// 0x2000c - 0x20000 = 0xc = 12
+// DISASMEXE-NEXT:    20000:   03 00 00 14     b       #12
+// 0x20030 - 0x20004 = 0x2c = 44
+// DISASMEXE-NEXT:    20004:   0b 00 00 14     b       #44
+// 0x20040 - 0x20008 = 0x38 = 56
+// DISASMEXE-NEXT:    20008:   0e 00 00 14     b       #56
+
+// DISASMEXE: foo:
+// DISASMEXE-NEXT:    2000c:   1f 20 03 d5     nop
+
+// DISASMEXE: Disassembly of section .plt:
+// DISASMEXE-NEXT: .plt:
+// DISASMEXE-NEXT:    20010:   f0 7b bf a9     stp     x16, x30, [sp, #-16]!
+// &(.got.plt[2]) = 0x300B0 + 2 * 8 = 0x300C0
+// Page(0x30010) - Page(0x20014) = 0x30000 - 0x20000 = 0x10000 = 65536
+// DISASMEXE-NEXT:    20014:   90 00 00 90     adrp    x16, #65536
+// 0x120c0 & 0xFFF = 0xC0 = 192
+// DISASMEXE-NEXT:    20018:   11 0a 40 f9     ldr     x17, [x16, #16]
+// DISASMEXE-NEXT:    2001c:   10 42 00 91     add     x16, x16, #16
+// DISASMEXE-NEXT:    20020:   20 02 1f d6     br      x17
+// DISASMEXE-NEXT:    20024:   1f 20 03 d5     nop
+// DISASMEXE-NEXT:    20028:   1f 20 03 d5     nop
+// DISASMEXE-NEXT:    2002c:   1f 20 03 d5     nop
+
+// bar@plt
+// Page(0x40018) - Page(0x20030) = 0x30000 - 0x20000 = 0x10000 = 65536
+// DISASMEXE-NEXT:    20030:   90 00 00 90     adrp    x16, #65536
+// DISASMEXE-NEXT:    20034:   11 0e 40 f9     ldr     x17, [x16, #24]
+// DISASMEXE-NEXT:    20038:   10 62 00 91     add     x16, x16, #24
+// DISASMEXE-NEXT:    2003c:   20 02 1f d6     br      x17
+
+// weak@plt
+// Page(0x40020) - Page(0x20040) = 0x30000 - 0x20000 = 0x10000 = 65536
+// DISASMEXE-NEXT:    20040:   90 00 00 90     adrp    x16, #65536
+// DISASMEXE-NEXT:    20044:   11 12 40 f9     ldr     x17, [x16, #32]
+// DISASMEXE-NEXT:    20048:   10 82 00 91     add     x16, x16, #32
+// DISASMEXE-NEXT:    2004c:   20 02 1f d6     br      x17
+
+.global _start,foo,bar
+.weak weak
+_start:
+  b foo
+  b bar
+  b weak
+
+.section .text2,"ax",@progbits
+foo:
+  nop
diff --git a/test/ELF/plt-i686.s b/test/ELF/plt-i686.s
new file mode 100644 (file)
index 0000000..9a2c7f5
--- /dev/null
@@ -0,0 +1,174 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// RUN: ld.lld -shared %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r %t | FileCheck --check-prefix=CHECKSHARED %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMSHARED %s
+// RUN: ld.lld -pie %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMPIE %s
+// REQUIRES: x86
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11020
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 48
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK:      Name: .got.plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 20
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+
+// 0x12000 + got.plt.reserved(12) = 0x1200C
+// 0x12000 + got.plt.reserved(12) + 4 = 0x12010
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.plt {
+// CHECK-NEXT:     0x1200C R_386_JUMP_SLOT bar 0x0
+// CHECK-NEXT:     0x12010 R_386_JUMP_SLOT zed 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+
+// 16 is the size of PLT[0]
+// (0x11010 + 16) - (0x11000 + 1) - 4 = 27
+// (0x11010 + 16) - (0x11005 + 1) - 4 = 22
+// (0x11020 + 16) - (0x1100a + 1) - 4 = 33
+
+// DISASM:       local:
+// DISASM-NEXT:  11000: {{.*}}
+// DISASM-NEXT:  11002: {{.*}}
+// DISASM:       _start:
+// 0x11013 + 5 - 24 = 0x11000
+// DISASM-NEXT: 11004: e9 27 00 00 00 jmp 39
+// DISASM-NEXT: 11009: e9 22 00 00 00 jmp 34
+// DISASM-NEXT: 1100e: e9 2d 00 00 00 jmp 45
+// DISASM-NEXT: 11013: e9 e8 ff ff ff jmp -24
+
+// 0x11010 - 0x1102b - 5 = -32
+// 0x11010 - 0x1103b - 5 = -48
+// 77828 = 0x13004 = .got.plt (0x13000) + 4
+// 77832 = 0x13008 = .got.plt (0x13000) + 8
+// 77836 = 0x1300C = .got.plt (0x13000) + got.plt.reserved(12)
+// 77840 = 0x13010 = .got.plt (0x13000) + got.plt.reserved(12) + 4
+// DISASM:      Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    11020: ff 35 04 20 01 00 pushl 73732
+// DISASM-NEXT:    11026: ff 25 08 20 01 00 jmpl *73736
+// DISASM-NEXT:    1102c: 90 nop
+// DISASM-NEXT:    1102d: 90 nop
+// DISASM-NEXT:    1102e: 90 nop
+// DISASM-NEXT:    1102f: 90 nop
+// DISASM-NEXT:    11030: ff 25 0c 20 01 00 jmpl *73740
+// DISASM-NEXT:    11036: 68 00 00 00 00 pushl $0
+// DISASM-NEXT:    1103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-NEXT:    11040: ff 25 10 20 01 00 jmpl *73744
+// DISASM-NEXT:    11046: 68 08 00 00 00 pushl $8
+// DISASM-NEXT:    1104b: e9 d0 ff ff ff jmp -48 <.plt>
+
+// CHECKSHARED:        Name: .plt
+// CHECKSHARED-NEXT:   Type: SHT_PROGBITS
+// CHECKSHARED-NEXT:   Flags [
+// CHECKSHARED-NEXT:     SHF_ALLOC
+// CHECKSHARED-NEXT:     SHF_EXECINSTR
+// CHECKSHARED-NEXT:   ]
+// CHECKSHARED-NEXT:   Address: 0x1020
+// CHECKSHARED-NEXT:   Offset: 0x1020
+// CHECKSHARED-NEXT:   Size: 48
+// CHECKSHARED-NEXT:   Link: 0
+// CHECKSHARED-NEXT:   Info: 0
+// CHECKSHARED-NEXT:   AddressAlignment: 16
+// CHECKSHARED-NEXT:   EntrySize: 0
+// CHECKSHARED-NEXT:   }
+// CHECKSHARED:        Name: .got.plt
+// CHECKSHARED-NEXT:   Type: SHT_PROGBITS
+// CHECKSHARED-NEXT:   Flags [
+// CHECKSHARED-NEXT:     SHF_ALLOC
+// CHECKSHARED-NEXT:     SHF_WRITE
+// CHECKSHARED-NEXT:   ]
+// CHECKSHARED-NEXT:   Address: 0x2000
+// CHECKSHARED-NEXT:   Offset: 0x2000
+// CHECKSHARED-NEXT:   Size: 20
+// CHECKSHARED-NEXT:   Link: 0
+// CHECKSHARED-NEXT:   Info: 0
+// CHECKSHARED-NEXT:   AddressAlignment: 4
+// CHECKSHARED-NEXT:   EntrySize: 0
+// CHECKSHARED-NEXT:   }
+
+// 0x2000 + got.plt.reserved(12) = 0x200C
+// 0x2000 + got.plt.reserved(12) + 4 = 0x2010
+// CHECKSHARED:        Relocations [
+// CHECKSHARED-NEXT:     Section ({{.*}}) .rel.plt {
+// CHECKSHARED-NEXT:       0x200C R_386_JUMP_SLOT bar 0x0
+// CHECKSHARED-NEXT:       0x2010 R_386_JUMP_SLOT zed 0x0
+// CHECKSHARED-NEXT:     }
+// CHECKSHARED-NEXT:   ]
+
+// DISASMSHARED:       local:
+// DISASMSHARED-NEXT:  1000: {{.*}}
+// DISASMSHARED-NEXT:  1002: {{.*}}
+// DISASMSHARED:       _start:
+// 0x1013 + 5 - 24 = 0x1000
+// DISASMSHARED-NEXT:  1004: e9 27 00 00 00 jmp 39
+// DISASMSHARED-NEXT:  1009: e9 22 00 00 00 jmp 34
+// DISASMSHARED-NEXT:  100e: e9 2d 00 00 00 jmp 45
+// DISASMSHARED-NEXT:  1013: e9 e8 ff ff ff jmp -24
+// DISASMSHARED-NEXT:  Disassembly of section .plt:
+// DISASMSHARED-NEXT:  .plt:
+// DISASMSHARED-NEXT:  1020: ff b3 04 20 00 00 pushl 8196(%ebx)
+// DISASMSHARED-NEXT:  1026: ff a3 08 20 00 00 jmpl *8200(%ebx)
+// DISASMSHARED-NEXT:  102c: 90 nop
+// DISASMSHARED-NEXT:  102d: 90 nop
+// DISASMSHARED-NEXT:  102e: 90 nop
+// DISASMSHARED-NEXT:  102f: 90 nop
+// DISASMSHARED-NEXT:  1030: ff a3 0c 20 00 00 jmpl *8204(%ebx)
+// DISASMSHARED-NEXT:  1036: 68 00 00 00 00     pushl $0
+// DISASMSHARED-NEXT:  103b: e9 e0 ff ff ff     jmp -32 <.plt>
+// DISASMSHARED-NEXT:  1040: ff a3 10 20 00 00 jmpl *8208(%ebx)
+// DISASMSHARED-NEXT:  1046: 68 08 00 00 00     pushl $8
+// DISASMSHARED-NEXT:  104b: e9 d0 ff ff ff     jmp -48 <.plt>
+
+// DISASMPIE:      Disassembly of section .plt:
+// DISASMPIE-NEXT: .plt:
+// DISASMPIE-NEXT:   1020:     ff b3 04 20 00 00 pushl 8196(%ebx)
+// DISASMPIE-NEXT:   1026:     ff a3 08 20 00 00 jmpl *8200(%ebx)
+// DISASMPIE-NEXT:   102c:     90 nop
+// DISASMPIE-NEXT:   102d:     90 nop
+// DISASMPIE-NEXT:   102e:     90 nop
+// DISASMPIE-NEXT:   102f:     90 nop
+// DISASMPIE-NEXT:   1030:     ff a3 0c 20 00 00 jmpl *8204(%ebx)
+// DISASMPIE-NEXT:   1036:     68 00 00 00 00 pushl $0
+// DISASMPIE-NEXT:   103b:     e9 e0 ff ff ff jmp -32 <.plt>
+// DISASMPIE-NEXT:   1040:     ff a3 10 20 00 00 jmpl *8208(%ebx)
+// DISASMPIE-NEXT:   1046:     68 08 00 00 00 pushl $8
+// DISASMPIE-NEXT:   104b:     e9 d0 ff ff ff jmp -48 <.plt>
+
+local:
+.long 0
+
+.global _start
+_start:
+  jmp bar@PLT
+  jmp bar@PLT
+  jmp zed@PLT
+  jmp local@plt
diff --git a/test/ELF/plt.s b/test/ELF/plt.s
new file mode 100644 (file)
index 0000000..4ab81aa
--- /dev/null
@@ -0,0 +1,119 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -shared %t.o %t2.so -o %t
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// RUN: llvm-readobj -s -r %t3 | FileCheck --check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM2 %s
+
+// REQUIRES: x86
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1020
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 64
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:     0x2018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT:     0x2020 R_X86_64_JUMP_SLOT zed 0x0
+// CHECK-NEXT:     0x2028 R_X86_64_JUMP_SLOT _start 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK2:      Name: .plt
+// CHECK2-NEXT: Type: SHT_PROGBITS
+// CHECK2-NEXT: Flags [
+// CHECK2-NEXT:   SHF_ALLOC
+// CHECK2-NEXT:   SHF_EXECINSTR
+// CHECK2-NEXT: ]
+// CHECK2-NEXT: Address: 0x201020
+// CHECK2-NEXT: Offset:
+// CHECK2-NEXT: Size: 48
+// CHECK2-NEXT: Link: 0
+// CHECK2-NEXT: Info: 0
+// CHECK2-NEXT: AddressAlignment: 16
+
+// CHECK2:      Relocations [
+// CHECK2-NEXT:   Section ({{.*}}) .rela.plt {
+// CHECK2-NEXT:     0x202018 R_X86_64_JUMP_SLOT bar 0x0
+// CHECK2-NEXT:     0x202020 R_X86_64_JUMP_SLOT zed 0x0
+// CHECK2-NEXT:   }
+// CHECK2-NEXT: ]
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+
+// 0x1030 - (0x1000 + 5) = 43
+// 0x1030 - (0x1005 + 5) = 38
+// 0x1040 - (0x100a + 5) = 49
+// 0x1048 - (0x100a + 5) = 60
+
+// DISASM:      _start:
+// DISASM-NEXT:   1000:  e9 {{.*}}       jmp  43
+// DISASM-NEXT:   1005:  e9 {{.*}}       jmp  38
+// DISASM-NEXT:   100a:  e9 {{.*}}       jmp  49
+// DISASM-NEXT:   100f:  e9 {{.*}}       jmp  60
+
+// 0x2018 - 0x1036  = 4066
+// 0x2020 - 0x1046  = 4058
+// 0x2028 - 0x1056  = 4050
+
+// DISASM:      Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:   1020:  ff 35 e2 0f 00 00  pushq 4066(%rip)
+// DISASM-NEXT:   1026:  ff 25 e4 0f 00 00  jmpq *4068(%rip)
+// DISASM-NEXT:   102c:  0f 1f 40 00        nopl (%rax)
+// DISASM-NEXT:   1030:  ff 25 e2 0f 00 00  jmpq *4066(%rip)
+// DISASM-NEXT:   1036:  68 00 00 00 00     pushq $0
+// DISASM-NEXT:   103b:  e9 e0 ff ff ff     jmp -32 <.plt>
+// DISASM-NEXT:   1040:  ff 25 da 0f 00 00  jmpq *4058(%rip)
+// DISASM-NEXT:   1046:  68 01 00 00 00     pushq $1
+// DISASM-NEXT:   104b:  e9 d0 ff ff ff     jmp -48 <.plt>
+// DISASM-NEXT:   1050:  ff 25 d2 0f 00 00  jmpq *4050(%rip)
+// DISASM-NEXT:   1056:  68 02 00 00 00     pushq $2
+// DISASM-NEXT:   105b:  e9 c0 ff ff ff     jmp -64 <.plt>
+
+// 0x201030 - (0x201000 + 1) - 4 = 43
+// 0x201030 - (0x201005 + 1) - 4 = 38
+// 0x201040 - (0x20100a + 1) - 4 = 49
+// 0x201000 - (0x20100f + 1) - 4 = -20
+
+// DISASM2:      _start:
+// DISASM2-NEXT:   201000:  e9 {{.*}}     jmp  43
+// DISASM2-NEXT:   201005:  e9 {{.*}}     jmp  38
+// DISASM2-NEXT:   20100a:  e9 {{.*}}     jmp  49
+// DISASM2-NEXT:   20100f:  e9 {{.*}}     jmp  -20
+
+// 0x202018 - 0x201036  = 4066
+// 0x202020 - 0x201046  = 4058
+
+// DISASM2:      Disassembly of section .plt:
+// DISASM2-NEXT: .plt:
+// DISASM2-NEXT:  201020:  ff 35 e2 0f 00 00   pushq 4066(%rip)
+// DISASM2-NEXT:  201026:  ff 25 e4 0f 00 00   jmpq *4068(%rip)
+// DISASM2-NEXT:  20102c:  0f 1f 40 00         nopl  (%rax)
+// DISASM2-NEXT:  201030:  ff 25 e2 0f 00 00   jmpq *4066(%rip)
+// DISASM2-NEXT:  201036:  68 00 00 00 00      pushq $0
+// DISASM2-NEXT:  20103b:  e9 e0 ff ff ff      jmp -32 <.plt>
+// DISASM2-NEXT:  201040:  ff 25 da 0f 00 00   jmpq *4058(%rip)
+// DISASM2-NEXT:  201046:  68 01 00 00 00      pushq $1
+// DISASM2-NEXT:  20104b:  e9 d0 ff ff ff      jmp -48 <.plt>
+// DISASM2-NOT:   2010C0
+
+.global _start
+_start:
+  jmp bar@PLT
+  jmp bar@PLT
+  jmp zed@PLT
+  jmp _start@plt
diff --git a/test/ELF/ppc-relocs.s b/test/ELF/ppc-relocs.s
new file mode 100644 (file)
index 0000000..78542dd
--- /dev/null
@@ -0,0 +1,64 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+.section .R_PPC_ADDR16_HA,"ax",@progbits
+.globl _start
+_start:
+  lis 4, msg@ha
+msg:
+  .string "foo"
+  len = . - msg
+
+# CHECK: Disassembly of section .R_PPC_ADDR16_HA:
+# CHECK: _start:
+# CHECK:    11000:       3c 80 00 01     lis 4, 1
+# CHECK: msg:
+# CHECK:    11004:       66 6f 6f 00     oris 15, 19, 28416
+
+.section .R_PPC_ADDR16_LO,"ax",@progbits
+  addi 4, 4, msg@l
+mystr:
+  .asciz "blah"
+  len = . - mystr
+
+# CHECK: Disassembly of section .R_PPC_ADDR16_LO:
+# CHECK: .R_PPC_ADDR16_LO:
+# CHECK:    11008:       38 84 10 04     addi 4, 4, 4100
+# CHECK: mystr:
+# CHECK:    1100c:       62 6c 61 68     ori 12, 19, 24936
+
+.align  2
+.section .R_PPC_REL24,"ax",@progbits
+.globl .FR_PPC_REL24
+.FR_PPC_REL24:
+  b .Lfoox
+.section .R_PPC_REL24_2,"ax",@progbits
+.Lfoox:
+
+# CHECK: Disassembly of section .R_PPC_REL24:
+# CHECK: .FR_PPC_REL24:
+# CHECK:    11014:       48 00 00 04     b .+4
+
+.section .R_PPC_REL32,"ax",@progbits
+.globl .FR_PPC_REL32
+.FR_PPC_REL32:
+  .long .Lfoox3 - .
+.section .R_PPC_REL32_2,"ax",@progbits
+.Lfoox3:
+
+# CHECK: Disassembly of section .R_PPC_REL32:
+# CHECK: .FR_PPC_REL32:
+# CHECK:    11018:       00 00 00 04
+
+.section .R_PPC_ADDR32,"ax",@progbits
+.globl .FR_PPC_ADDR32
+.FR_PPC_ADDR32:
+  .long .Lfoox2
+.section .R_PPC_ADDR32_2,"ax",@progbits
+.Lfoox2:
+
+# CHECK: Disassembly of section .R_PPC_ADDR32:
+# CHECK: .FR_PPC_ADDR32:
+# CHECK:    1101c:       00 01 10 20
diff --git a/test/ELF/ppc64-addr16-error.s b/test/ELF/ppc64-addr16-error.s
new file mode 100644 (file)
index 0000000..2bc8ef2
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2
+// RUN: not ld.lld -shared %t %t2 -o %t3 2>&1 | FileCheck %s
+// REQUIRES: ppc
+
+.short sym+65539
+
+// CHECK: relocation R_PPC64_ADDR16 out of range
diff --git a/test/ELF/ppc64-rel-calls.s b/test/ELF/ppc64-rel-calls.s
new file mode 100644 (file)
index 0000000..f3b309f
--- /dev/null
@@ -0,0 +1,42 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# CHECK: Disassembly of section .text:
+
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+.text
+.Lfoo:
+  li      0,1
+  li      3,42
+  sc
+
+# CHECK: 10010000:       38 00 00 01     li 0, 1
+# CHECK: 10010004:       38 60 00 2a     li 3, 42
+# CHECK: 10010008:       44 00 00 02     sc
+
+.section        ".opd","aw"
+.global bar
+bar:
+.quad   .Lbar,.TOC.@tocbase,0
+
+.text
+.Lbar:
+  bl _start
+  nop
+  bl .Lfoo
+  nop
+  blr
+
+# FIXME: The printing here is misleading, the branch offset here is negative.
+# CHECK: 1001000c:       4b ff ff f5     bl .+67108852
+# CHECK: 10010010:       60 00 00 00     nop
+# CHECK: 10010014:       4b ff ff ed     bl .+67108844
+# CHECK: 10010018:       60 00 00 00     nop
+# CHECK: 1001001c:       4e 80 00 20     blr
+
diff --git a/test/ELF/ppc64-relocs.s b/test/ELF/ppc64-relocs.s
new file mode 100644 (file)
index 0000000..cb6177d
--- /dev/null
@@ -0,0 +1,130 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+.text
+.Lfoo:
+       li      0,1
+       li      3,42
+       sc
+
+.section        ".toc","aw"
+.L1:
+.quad           22, 37, 89, 47
+
+.section .R_PPC64_TOC16_LO_DS,"ax",@progbits
+.globl .FR_PPC64_TOC16_LO_DS
+.FR_PPC64_TOC16_LO_DS:
+  ld 1, .L1@toc@l(2)
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_LO_DS:
+# CHECK: .FR_PPC64_TOC16_LO_DS:
+# CHECK: 1001000c:       e8 22 80 00     ld 1, -32768(2)
+
+.section .R_PPC64_TOC16_LO,"ax",@progbits
+.globl .FR_PPC64_TOC16_LO
+.FR_PPC64_TOC16_LO:
+  addi  1, 2, .L1@toc@l
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_LO:
+# CHECK: .FR_PPC64_TOC16_LO:
+# CHECK: 10010010: 38 22 80 00 addi 1, 2, -32768
+
+.section .R_PPC64_TOC16_HI,"ax",@progbits
+.globl .FR_PPC64_TOC16_HI
+.FR_PPC64_TOC16_HI:
+  addis 1, 2, .L1@toc@h
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_HI:
+# CHECK: .FR_PPC64_TOC16_HI:
+# CHECK: 10010014: 3c 22 ff fe addis 1, 2, -2
+
+.section .R_PPC64_TOC16_HA,"ax",@progbits
+.globl .FR_PPC64_TOC16_HA
+.FR_PPC64_TOC16_HA:
+  addis 1, 2, .L1@toc@ha
+
+# CHECK: Disassembly of section .R_PPC64_TOC16_HA:
+# CHECK: .FR_PPC64_TOC16_HA:
+# CHECK: 10010018: 3c 22 ff ff addis 1, 2, -1
+
+.section .R_PPC64_REL24,"ax",@progbits
+.globl .FR_PPC64_REL24
+.FR_PPC64_REL24:
+  b .Lfoox
+.section .R_PPC64_REL24_2,"ax",@progbits
+.Lfoox:
+
+# CHECK: Disassembly of section .R_PPC64_REL24:
+# CHECK: .FR_PPC64_REL24:
+# CHECK: 1001001c: 48 00 00 04 b .+4
+
+.section .R_PPC64_ADDR16_LO,"ax",@progbits
+.globl .FR_PPC64_ADDR16_LO
+.FR_PPC64_ADDR16_LO:
+  li 1, .Lfoo@l
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_LO:
+# CHECK: .FR_PPC64_ADDR16_LO:
+# CHECK: 10010020: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HI,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HI
+.FR_PPC64_ADDR16_HI:
+  li 1, .Lfoo@h
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HI:
+# CHECK: .FR_PPC64_ADDR16_HI:
+# CHECK: 10010024: 38 20 10 01 li 1, 4097
+
+.section .R_PPC64_ADDR16_HA,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HA
+.FR_PPC64_ADDR16_HA:
+  li 1, .Lfoo@ha
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HA:
+# CHECK: .FR_PPC64_ADDR16_HA:
+# CHECK: 10010028: 38 20 10 01 li 1, 4097
+
+.section .R_PPC64_ADDR16_HIGHER,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHER
+.FR_PPC64_ADDR16_HIGHER:
+  li 1, .Lfoo@higher
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHER:
+# CHECK: .FR_PPC64_ADDR16_HIGHER:
+# CHECK: 1001002c: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHERA
+.FR_PPC64_ADDR16_HIGHERA:
+  li 1, .Lfoo@highera
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHERA:
+# CHECK: .FR_PPC64_ADDR16_HIGHERA:
+# CHECK: 10010030: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHEST
+.FR_PPC64_ADDR16_HIGHEST:
+  li 1, .Lfoo@highest
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHEST:
+# CHECK: .FR_PPC64_ADDR16_HIGHEST:
+# CHECK: 10010034: 38 20 00 00 li 1, 0
+
+.section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits
+.globl .FR_PPC64_ADDR16_HIGHESTA
+.FR_PPC64_ADDR16_HIGHESTA:
+  li 1, .Lfoo@highesta
+
+# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHESTA:
+# CHECK: .FR_PPC64_ADDR16_HIGHESTA:
+# CHECK: 10010038: 38 20 00 00 li 1, 0
+
diff --git a/test/ELF/ppc64-shared-rel-toc.s b/test/ELF/ppc64-shared-rel-toc.s
new file mode 100644 (file)
index 0000000..445011b
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+// REQUIRES: ppc
+
+// When we create the TOC reference in the shared library, make sure that the
+// R_PPC64_RELATIVE relocation uses the correct (non-zero) offset.
+
+        .globl  foo
+        .align  2
+        .type   foo,@function
+        .section        .opd,"aw",@progbits
+foo:                                    # @foo
+        .align  3
+        .quad   .Lfunc_begin0
+        .quad   .TOC.@tocbase
+        .quad   0
+        .text
+.Lfunc_begin0:
+        blr
+
+// CHECK: 0x20000 R_PPC64_RELATIVE - 0x10000
+// CHECK: 0x20008 R_PPC64_RELATIVE - 0x8000
+
+// CHECK: Name: foo
+// CHECK-NEXT: Value: 0x20000
+
diff --git a/test/ELF/ppc64-toc-restore.s b/test/ELF/ppc64-toc-restore.s
new file mode 100644 (file)
index 0000000..0c3d30b
--- /dev/null
@@ -0,0 +1,62 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// REQUIRES: ppc
+
+// CHECK: Disassembly of section .text:
+
+.global _start
+_start:
+  bl bar
+  nop
+
+// CHECK: _start:
+// CHECK: 10010000:       48 00 00 21     bl .+32
+// CHECK-NOT: 10010004:       60 00 00 00     nop
+// CHECK: 10010004:       e8 41 00 28     ld 2, 40(1)
+
+.global noret
+noret:
+  bl bar
+  li 5, 7
+
+// CHECK: noret:
+// CHECK: 10010008: 48 00 00 19 bl .+24
+// CHECK: 1001000c: 38 a0 00 07 li 5, 7
+
+.global noretend
+noretend:
+  bl bar
+
+// CHECK: noretend:
+// CHECK: 10010010: 48 00 00 11 bl .+16
+
+.global noretb
+noretb:
+  b bar
+
+// CHECK: noretb:
+// CHECK: 10010014: 48 00 00 0c b .+12
+
+// This should come last to check the end-of-buffer condition.
+.global last
+last:
+  bl bar
+  nop
+
+// CHECK: last:
+// CHECK: 10010018: 48 00 00 09 bl .+8
+// CHECK: 1001001c: e8 41 00 28 ld 2, 40(1)
+
+// CHECK: Disassembly of section .plt:
+// CHECK: .plt:
+// CHECK: 10010020:       f8 41 00 28     std 2, 40(1)
+// CHECK: 10010024:       3d 62 10 02     addis 11, 2, 4098
+// CHECK: 10010028:       e9 8b 80 18     ld 12, -32744(11)
+// CHECK: 1001002c:       e9 6c 00 00     ld 11, 0(12)
+// CHECK: 10010030:       7d 69 03 a6     mtctr 11
+// CHECK: 10010034:       e8 4c 00 08     ld 2, 8(12)
+// CHECK: 10010038:       e9 6c 00 10     ld 11, 16(12)
+// CHECK: 1001003c:       4e 80 04 20     bctr
diff --git a/test/ELF/ppc64-weak-undef-call-shared.s b/test/ELF/ppc64-weak-undef-call-shared.s
new file mode 100644 (file)
index 0000000..2c27a27
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+# REQUIRES: ppc
+
+.section        ".toc","aw"
+.quad weakfunc
+// CHECK-NOT: R_PPC64_RELATIVE
+
+.text
+.Lfoo:
+  bl weakfunc
+// CHECK-NOT: R_PPC64_REL24
+
+.weak weakfunc
+
diff --git a/test/ELF/ppc64-weak-undef-call.s b/test/ELF/ppc64-weak-undef-call.s
new file mode 100644 (file)
index 0000000..55443cb
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# CHECK: Disassembly of section .text:
+
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC.@tocbase,0
+
+.text
+.Lfoo:
+  bl weakfunc
+  nop
+  blr
+
+.weak weakfunc
+
+# It does not really matter how we fixup the bl, if at all, because it needs to
+# be unreachable. But, we should link successfully. We should not, however,
+# generate a .plt entry (this would be wasted space). For now, we do nothing
+# (leaving the zero relative offset present in the input).
+# CHECK: 10010000:       48 00 00 01     bl .+0
+# CHECK: 10010004:       60 00 00 00     nop
+# CHECK: 10010008:       4e 80 00 20     blr
diff --git a/test/ELF/pre_init_fini_array.s b/test/ELF/pre_init_fini_array.s
new file mode 100644 (file)
index 0000000..1192fd0
--- /dev/null
@@ -0,0 +1,152 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2
+// RUN: ld.lld %t2 -o %t2.so -shared
+// RUN: ld.lld %t %t2.so -o %t2
+// RUN: llvm-readobj -r -symbols -sections -dynamic-table %t2 | FileCheck %s
+// RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  call __preinit_array_start
+  call __preinit_array_end
+  call __init_array_start
+  call __init_array_end
+  call __fini_array_start
+  call __fini_array_end
+
+
+.section .init_array,"aw",@init_array
+  .quad 0
+
+.section .preinit_array,"aw",@preinit_array
+        .quad 0
+        .byte 0
+
+.section .fini_array,"aw",@fini_array
+        .quad 0
+        .short 0
+
+// CHECK:      Name: .init_array
+// CHECK-NEXT: Type: SHT_INIT_ARRAY
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[INIT_ADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[INIT_SIZE:.*]]
+
+
+// CHECK:     Name: .preinit_array
+// CHECK-NEXT: Type: SHT_PREINIT_ARRAY
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT: Address: [[PREINIT_ADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[PREINIT_SIZE:.*]]
+
+
+// CHECK:      Name: .fini_array
+// CHECK-NEXT: Type: SHT_FINI_ARRAY
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[FINI_ADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[FINI_SIZE:.*]]
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
+
+// CHECK:        Name: __fini_array_end
+// CHECK-NEXT:   Value: 0x20201B
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .fini_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __fini_array_start
+// CHECK-NEXT:   Value: [[FINI_ADDR]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .fini_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __init_array_end
+// CHECK-NEXT:   Value: 0x202008
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .init_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __init_array_start
+// CHECK-NEXT:   Value: [[INIT_ADDR]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .init_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __preinit_array_end
+// CHECK-NEXT:   Value: 0x202011
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .preinit_array
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: __preinit_array_start
+// CHECK-NEXT:   Value: [[PREINIT_ADDR]]
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other [
+// CHECK-NEXT:     STV_HIDDEN
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Section: .preinit_array
+// CHECK-NEXT: }
+
+// CHECK: DynamicSection
+// CHECK: PREINIT_ARRAY        [[PREINIT_ADDR]]
+// CHECK: PREINIT_ARRAYSZ      [[PREINIT_SIZE]] (bytes)
+// CHECK: INIT_ARRAY           [[INIT_ADDR]]
+// CHECK: INIT_ARRAYSZ         [[INIT_SIZE]] (bytes)
+// CHECK: FINI_ARRAY           [[FINI_ADDR]]
+// CHECK: FINI_ARRAYSZ         [[FINI_SIZE]] (bytes)
+
+
+// 0x202008 - (0x201000 + 5) = 4099
+// 0x202011 - (0x201005 + 5) = 4103
+// 0x202000 - (0x20100a + 5) = 4081
+// 0x202008 - (0x20100f + 5) = 4084
+// 0x202011 - (0x201014 + 5) = 4088
+// 0x20201B - (0x201019 + 5) = 4093
+// DISASM:      _start:
+// DISASM-NEXT:   201000:  e8 {{.*}}  callq  4099
+// DISASM-NEXT:   201005:  e8 {{.*}}  callq  4103
+// DISASM-NEXT:   20100a:  e8 {{.*}}  callq  4081
+// DISASM-NEXT:   20100f:  e8 {{.*}}  callq  4084
+// DISASM-NEXT:   201014:  e8 {{.*}}  callq  4088
+// DISASM-NEXT:   201019:  e8 {{.*}}  callq  4093
diff --git a/test/ELF/pre_init_fini_array_missing.s b/test/ELF/pre_init_fini_array_missing.s
new file mode 100644 (file)
index 0000000..7dabfa7
--- /dev/null
@@ -0,0 +1,43 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// RUN: ld.lld -pie %t -o %t3
+// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=PIE %s
+// REQUIRES: x86
+
+.globl _start
+_start:
+  call __preinit_array_start
+  call __preinit_array_end
+  call __init_array_start
+  call __init_array_end
+  call __fini_array_start
+  call __fini_array_end
+
+// With no .init_array section the symbols resolve to 0
+// 0 - (0x201000 + 5) = -2101253
+// 0 - (0x201005 + 5) = -2101258
+// 0 - (0x20100a + 5) = -2101263
+// 0 - (0x20100f + 5) = -2101268
+// 0 - (0x201014 + 5) = -2101273
+// 0 - (0x201019 + 5) = -2101278
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT:  _start:
+// CHECK-NEXT:   201000:    e8 fb ef df ff     callq    -2101253
+// CHECK-NEXT:   201005:    e8 f6 ef df ff     callq    -2101258
+// CHECK-NEXT:   20100a:    e8 f1 ef df ff     callq    -2101263
+// CHECK-NEXT:   20100f:    e8 ec ef df ff     callq    -2101268
+// CHECK-NEXT:   201014:    e8 e7 ef df ff     callq    -2101273
+// CHECK-NEXT:   201019:    e8 e2 ef df ff     callq    -2101278
+
+// In position-independent binaries, they resolve to the image base.
+
+// PIE:      Disassembly of section .text:
+// PIE-NEXT: _start:
+// PIE-NEXT:     1000: e8 fb ef ff ff  callq   -4101
+// PIE-NEXT:     1005: e8 f6 ef ff ff  callq   -4106
+// PIE-NEXT:     100a: e8 f1 ef ff ff  callq   -4111
+// PIE-NEXT:     100f: e8 ec ef ff ff  callq   -4116
+// PIE-NEXT:     1014: e8 e7 ef ff ff  callq   -4121
+// PIE-NEXT:     1019: e8 e2 ef ff ff  callq   -4126
diff --git a/test/ELF/progname.s b/test/ELF/progname.s
new file mode 100644 (file)
index 0000000..be8ab9e
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: echo .global __progname > %t2.s
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -o %t %t.o %t2.so
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+// RUN: echo "VER_1 { global: bar; };" > %t.script
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
+// RUN:   %p/Inputs/progname-ver.s -o %t-ver.o
+// RUN: ld.lld -shared -o %t.so -version-script %t.script %t-ver.o
+// RUN: ld.lld -o %t %t.o %t.so
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+// RUN: echo "{ _start; };" > %t.dynlist
+// RUN: ld.lld -dynamic-list %t.dynlist -o %t %t.o %t.so
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+// CHECK:      Name:     __progname@
+// CHECK-NEXT: Value:    0x201000
+// CHECK-NEXT: Size:     0
+// CHECK-NEXT: Binding:  Global (0x1)
+// CHECK-NEXT: Type:     None (0x0)
+// CHECK-NEXT: Other:    0
+// CHECK-NEXT: Section:  .text
+// CHECK-NEXT: }
+
+.global _start, __progname
+_start:
+__progname:
+  nop
diff --git a/test/ELF/program-header-layout.s b/test/ELF/program-header-layout.s
new file mode 100644 (file)
index 0000000..57759c9
--- /dev/null
@@ -0,0 +1,85 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -sections -program-headers %t2 | FileCheck %s
+# REQUIRES: x86
+
+# Check that different output sections with the same flags are merged into a
+# single Read/Write PT_LOAD.
+
+.section .r,"a"
+.globl _start
+_start:
+.quad 0
+
+.section .a,"aw"
+.quad 1
+
+.section .b,"aw"
+.quad 2
+
+# CHECK:        Name: .r
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset: 0x158
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment:
+# CHECK-NEXT:   EntrySize:
+# CHECK-NEXT: }
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_PHDR (0x6)
+# CHECK-NEXT:     Offset: 0x40
+# CHECK-NEXT:     VirtualAddress: 0x200040
+# CHECK-NEXT:     PhysicalAddress: 0x200040
+# CHECK-NEXT:     FileSize: 280
+# CHECK-NEXT:     MemSize: 280
+# CHECK-NEXT:     Flags [ (0x4)
+# CHECK-NEXT:       PF_R (0x4)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 8
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress:
+# CHECK-NEXT:     PhysicalAddress:
+# CHECK-NEXT:     FileSize: 352
+# CHECK-NEXT:     MemSize: 352
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_LOAD
+# CHECK-NEXT:     Offset:
+# CHECK-NEXT:     VirtualAddress:
+# CHECK-NEXT:     PhysicalAddress:
+# CHECK-NEXT:     FileSize: 16
+# CHECK-NEXT:     MemSize: 16
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   ProgramHeader {
+# CHECK-NEXT:     Type: PT_GNU_STACK
+# CHECK-NEXT:     Offset: 0x0
+# CHECK-NEXT:     VirtualAddress: 0x0
+# CHECK-NEXT:     PhysicalAddress: 0x0
+# CHECK-NEXT:     FileSize: 0
+# CHECK-NEXT:     MemSize: 0
+# CHECK-NEXT:     Flags [
+# CHECK-NEXT:       PF_R
+# CHECK-NEXT:       PF_W
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Alignment: 0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/protected-shared.s b/test/ELF/protected-shared.s
new file mode 100644 (file)
index 0000000..e69b108
--- /dev/null
@@ -0,0 +1,52 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/protected-shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t
+// RUN: llvm-readobj -t --dyn-symbols %t | FileCheck %s
+
+        .global  _start
+_start:
+
+        .global bar
+bar:
+
+        .data
+        .quad foo
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .text
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/rel-offset.s b/test/ELF/rel-offset.s
new file mode 100644 (file)
index 0000000..8044e61
--- /dev/null
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-readobj -r  %t | FileCheck %s
+
+        .section        .data.foo,"aw",@progbits
+        .quad   foo
+
+        .section        .data.zed,"aw",@progbits
+        .quad   foo
+
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   0x1000 R_X86_64_64 foo 0x0
+// CHECK-NEXT:   0x1008 R_X86_64_64 foo 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/relative-dynamic-reloc-pie.s b/test/ELF/relative-dynamic-reloc-pie.s
new file mode 100644 (file)
index 0000000..f7c8b3c
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t.pie
+# RUN: llvm-readobj -r -dyn-symbols %t.pie | FileCheck %s
+
+## Test that we create R_X86_64_RELATIVE relocations with -pie.
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x2000 R_X86_64_RELATIVE - 0x2000
+# CHECK-NEXT:     0x2008 R_X86_64_RELATIVE - 0x2008
+# CHECK-NEXT:     0x2010 R_X86_64_RELATIVE - 0x2009
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.globl _start
+_start:
+nop
+
+ .data
+foo:
+ .quad foo
+
+.hidden bar
+.global bar
+bar:
+ .quad bar
+ .quad bar + 1
diff --git a/test/ELF/relative-dynamic-reloc-ppc64.s b/test/ELF/relative-dynamic-reloc-ppc64.s
new file mode 100644 (file)
index 0000000..65d0e8e
--- /dev/null
@@ -0,0 +1,67 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+// REQUIRES: ppc
+
+// Test that we create R_PPC64_RELATIVE relocations but don't put any
+// symbols in the dynamic symbol table.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x[[FOO_ADDR:.*]] R_PPC64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x[[BAR_ADDR:.*]] R_PPC64_RELATIVE - 0x[[BAR_ADDR]]
+// CHECK-NEXT:     0x10010 R_PPC64_RELATIVE - 0x10009
+// CHECK-NEXT:     0x{{.*}} R_PPC64_RELATIVE - 0x[[ZED_ADDR:.*]]
+// CHECK-NEXT:     0x{{.*}} R_PPC64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x10028 R_PPC64_ADDR64 external 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Symbols [
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value: 0x[[FOO_ADDR]]
+// CHECK:        Name: bar
+// CHECK-NEXT:   Value: 0x[[BAR_ADDR]]
+// CHECK:        Name: zed
+// CHECK-NEXT:   Value: 0x[[ZED_ADDR]]
+// CHECK:      ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: external@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .data
+foo:
+        .quad foo
+
+        .hidden bar
+        .global bar
+bar:
+        .quad bar
+        .quad bar + 1
+
+        .hidden zed
+        .comm zed,1
+        .quad zed
+
+        .section abc,"aw"
+        .quad foo
+
+        .quad external
diff --git a/test/ELF/relative-dynamic-reloc.s b/test/ELF/relative-dynamic-reloc.s
new file mode 100644 (file)
index 0000000..0ed7e40
--- /dev/null
@@ -0,0 +1,71 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s
+
+// Test that we create R_X86_64_RELATIVE relocations but don't put any
+// symbols in the dynamic symbol table.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x[[FOO_ADDR:.*]] R_X86_64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x[[BAR_ADDR:.*]] R_X86_64_RELATIVE - 0x[[BAR_ADDR]]
+// CHECK-NEXT:     0x1010 R_X86_64_RELATIVE - 0x1009
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x[[ZED_ADDR:.*]]
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x[[FOO_ADDR]]
+// CHECK-NEXT:     0x1028 R_X86_64_64 external 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      Symbols [
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value: 0x[[FOO_ADDR]]
+// CHECK:        Name: bar
+// CHECK-NEXT:   Value: 0x[[BAR_ADDR]]
+// CHECK:        Name: zed
+// CHECK-NEXT:   Value: 0x[[ZED_ADDR]]
+// CHECK:      ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: external@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .data
+foo:
+        .quad foo
+
+        .hidden bar
+        .global bar
+bar:
+        .quad bar
+        .quad bar + 1
+
+        .hidden zed
+        .comm zed,1
+        .quad zed
+
+        .section abc,"aw"
+        .quad foo
+
+        .quad external
+
+// This doesn't need a relocation.
+        callq localfunc@PLT
+localfunc:
diff --git a/test/ELF/relocatable-bss.s b/test/ELF/relocatable-bss.s
new file mode 100644 (file)
index 0000000..becfbae
--- /dev/null
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld -r %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+## We check here that .bss does not occupy the space in file.
+## If it would, the SectionHeaderOffset would have offset about 5 megabytes.
+# CHECK:       ElfHeader {
+# CHECK-NEXT:  Ident {
+# CHECK-NEXT:    Magic: (7F 45 4C 46)
+# CHECK-NEXT:    Class: 64-bit
+# CHECK-NEXT:    DataEncoding: LittleEndian
+# CHECK-NEXT:    FileVersion: 1
+# CHECK-NEXT:    OS/ABI: SystemV
+# CHECK-NEXT:    ABIVersion: 0
+# CHECK-NEXT:    Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Type: Relocatable
+# CHECK-NEXT:  Machine: EM_X86_64
+# CHECK-NEXT:  Version:
+# CHECK-NEXT:  Entry:
+# CHECK-NEXT:   ProgramHeaderOffset:
+# CHECK-NEXT:   SectionHeaderOffset: 0xD8
+# CHECK-NEXT:  Flags [
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  HeaderSize:
+# CHECK-NEXT:  ProgramHeaderEntrySize:
+# CHECK-NEXT:  ProgramHeaderCount:
+# CHECK-NEXT:  SectionHeaderEntrySize:
+# CHECK-NEXT:  SectionHeaderCount:
+# CHECK-NEXT:  StringTableSectionIndex:
+# CHECK-NEXT:  }
+
+.text
+.globl _start
+_start:
+ nop
+
+.bss
+ .space 5242880
diff --git a/test/ELF/relocatable-comdat-multiple.s b/test/ELF/relocatable-comdat-multiple.s
new file mode 100644 (file)
index 0000000..4c3e7ce
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/relocatable-comdat-multiple.s -o %t2.o
+# RUN: ld.lld -r %t.o %t2.o -o %t
+# RUN: llvm-readobj -elf-section-groups %t | FileCheck %s
+
+# CHECK:      Groups {
+# CHECK-NEXT:   Group {
+# CHECK-NEXT:     Name: .group
+# CHECK-NEXT:     Index: 2
+# CHECK-NEXT:     Type: COMDAT
+# CHECK-NEXT:     Signature: aaa
+# CHECK-NEXT:     Section(s) in group [
+# CHECK-NEXT:       .text.a
+# CHECK-NEXT:       .text.b
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Group {
+# CHECK-NEXT:     Name: .group
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Type: COMDAT
+# CHECK-NEXT:     Signature: bbb
+# CHECK-NEXT:     Section(s) in group [
+# CHECK-NEXT:       .text.c
+# CHECK-NEXT:       .text.d
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT: }
+
+.section .text.a,"axG",@progbits,aaa,comdat
+.section .text.b,"axG",@progbits,aaa,comdat
diff --git a/test/ELF/relocatable-comdat.s b/test/ELF/relocatable-comdat.s
new file mode 100644 (file)
index 0000000..24504d2
--- /dev/null
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -r %t.o %t.o -o %t
+# RUN: llvm-readobj -elf-section-groups -sections %t | FileCheck %s
+
+# CHECK:        Name: .text.bar
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_EXECINSTR
+# CHECK-NEXT:     SHF_GROUP
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 8
+# CHECK:      Section {
+# CHECK-NEXT:   Index: 4
+# CHECK-NEXT:   Name: .text.foo
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_EXECINSTR
+# CHECK-NEXT:     SHF_GROUP
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size: 4
+
+# CHECK:       Groups {
+# CHECK-NEXT:    Group {
+# CHECK-NEXT:      Name: .group
+# CHECK-NEXT:      Index: 2
+# CHECK-NEXT:      Type: COMDAT
+# CHECK-NEXT:      Signature: abc
+# CHECK-NEXT:      Section(s) in group [
+# CHECK-NEXT:        .text.bar
+# CHECK-NEXT:        .text.foo
+# CHECK-NEXT:      ]
+# CHECK-NEXT:    }
+# CHECK-NEXT:  }
+
+.section .text.bar,"axG",@progbits,abc,comdat
+.quad 42
+.section .text.foo,"axG",@progbits,abc,comdat
+.long 42
diff --git a/test/ELF/relocatable-comment.s b/test/ELF/relocatable-comment.s
new file mode 100644 (file)
index 0000000..8ec22c2
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: ld.lld -r %t1.o -o %t
+# RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+# CHECK:      Name: .comment
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_MERGE
+# CHECK-NEXT:   SHF_STRINGS
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 7
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 1
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT:   0000: 666F6F62 617200                      |foobar.|
+# CHECK-NEXT: )
+
+
+# We used to crash creating a merge and non merge .comment sections.
+
+       .section        .comment,"MS",@progbits,1
+       .asciz  "foobar"
diff --git a/test/ELF/relocatable-common.s b/test/ELF/relocatable-common.s
new file mode 100644 (file)
index 0000000..3ead775
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld -r %t1.o -o %t
+# RUN: llvm-readobj -symbols -r %t | FileCheck %s
+# RUN: ld.lld -r --no-define-common %t1.o -o %t
+# RUN: llvm-readobj -symbols -r %t | FileCheck %s
+# RUN: ld.lld -r --define-common %t1.o -o %t
+# RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s
+# RUN: ld.lld -r -d %t1.o -o %t
+# RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s
+# RUN: ld.lld -r -dc %t1.o -o %t
+# RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s
+# RUN: ld.lld -r -dp %t1.o -o %t
+# RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s
+
+# CHECK:        Symbol {
+# CHECK:          Name: common
+# CHECK-NEXT:     Value: 0x4
+# CHECK-NEXT:     Size: 4
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Common (0xFFF2)
+# CHECK-NEXT:   }
+
+# DEFCOMM:      Symbol {
+# DEFCOMM:        Name: common
+# DEFCOMM-NEXT:   Value: 0x0
+# DEFCOMM-NEXT:   Size: 4
+# DEFCOMM-NEXT:   Binding: Global
+# DEFCOMM-NEXT:   Type: Object
+# DEFCOMM-NEXT:   Other: 0
+# DEFCOMM-NEXT:   Section: COMMON (0x2)
+# DEFCOMM-NEXT: }
+
+.comm common,4,4
diff --git a/test/ELF/relocatable-compressed-input.s b/test/ELF/relocatable-compressed-input.s
new file mode 100644 (file)
index 0000000..3c0199c
--- /dev/null
@@ -0,0 +1,45 @@
+# REQUIRES: x86, zlib
+
+# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t1
+# RUN: llvm-readobj -sections %t1 | FileCheck -check-prefix=GNU %s
+# GNU: Name: .zdebug_str
+
+# RUN: ld.lld %t1 -o %t2 -r
+# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s
+
+## Check we decompress section and remove ".z" prefix specific for zlib-gnu compression.
+# CHECK:      Section {
+# CHECK:        Index:
+# CHECK:        Name: .debug_str
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:     SHF_STRINGS
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link:
+# CHECK-NEXT:   Info:
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 1
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: {{.*}}  |short unsigned i|
+# CHECK-NEXT:     0010: {{.*}}  |nt.unsigned int.|
+# CHECK-NEXT:     0020: {{.*}}  |long unsigned in|
+# CHECK-NEXT:     0030: {{.*}}  |t.char.unsigned |
+# CHECK-NEXT:     0040: {{.*}}  |char.|
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+
+.section .debug_str,"MS",@progbits,1
+.LASF2:
+ .string "short unsigned int"
+.LASF3:
+ .string "unsigned int"
+.LASF0:
+ .string "long unsigned int"
+.LASF8:
+ .string "char"
+.LASF1:
+ .string "unsigned char"
diff --git a/test/ELF/relocatable-eh-frame-hdr.s b/test/ELF/relocatable-eh-frame-hdr.s
new file mode 100644 (file)
index 0000000..f7b5724
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --eh-frame-hdr -r %t.o -o %t
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK:       Sections [
+# CHECK-NOT:    Name: .eh_frame_hdr
+
+.section .foo,"ax",@progbits
+.cfi_startproc
+.cfi_endproc
diff --git a/test/ELF/relocatable-eh-frame.s b/test/ELF/relocatable-eh-frame.s
new file mode 100644 (file)
index 0000000..c2e5ec6
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -r %t.o %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+# RUN: ld.lld %t -o %t.so -shared
+# RUN: llvm-objdump -h %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO: .eh_frame     00000030
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.eh_frame {
+# CHECK-NEXT:     0x20 R_X86_64_PC32 .foo 0x0
+# CHECK-NEXT:     0x50 R_X86_64_NONE - 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.section .foo,"aG",@progbits,bar,comdat
+.cfi_startproc
+.cfi_endproc
diff --git a/test/ELF/relocatable-ehframe.s b/test/ELF/relocatable-ehframe.s
new file mode 100644 (file)
index 0000000..2d302e5
--- /dev/null
@@ -0,0 +1,51 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable-ehframe.s -o %t2.o
+# RUN: ld.lld -r %t1.o %t2.o -o %t
+# RUN: llvm-readobj -r -s -section-data %t | FileCheck %s
+
+# CHECK:      Name: .strtab
+# CHECK-NEXT: Type: SHT_STRTAB
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 1
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT:   0000: 005F7374 61727400                 |._start.|
+# CHECK-NEXT: )
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section {{.*}} .rela.eh_frame {
+# CHECK-NEXT:     0x20 R_X86_64_PC32 foo 0x0
+# CHECK-NEXT:     0x34 R_X86_64_PC32 bar 0x0
+# CHECK-NEXT:     0x48 R_X86_64_PC32 dah 0x0
+# CHECK-NEXT:     0x78 R_X86_64_PC32 foo1 0x0
+# CHECK-NEXT:     0x8C R_X86_64_PC32 bar1 0x0
+# CHECK-NEXT:     0xA0 R_X86_64_PC32 dah1 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.section foo,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section bar,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.section dah,"ax",@progbits
+.cfi_startproc
+ nop
+.cfi_endproc
+
+.text
+.globl _start
+_start:
+ nop
diff --git a/test/ELF/relocatable-empty-archive.s b/test/ELF/relocatable-empty-archive.s
new file mode 100644 (file)
index 0000000..545ef7b
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: rm -f %t.a
+# RUN: llvm-ar rc %t.a
+# RUN: ld.lld -m elf_x86_64 %t.a -o %t -r
+# RUN: llvm-readobj -file-headers %t | FileCheck %s
+
+# CHECK: Format: ELF64-x86-64
+# CHECK: Arch: x86_64
+# CHECK: AddressSize: 64bit
+# CHECK: Type: Relocatable
diff --git a/test/ELF/relocatable-local-sym.s b/test/ELF/relocatable-local-sym.s
new file mode 100644 (file)
index 0000000..b894d6b
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: ld.lld -r %t1.o -o %t2.o
+# RUN: llvm-readobj -r %t2.o | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.text {
+# CHECK-NEXT:     0x3 R_X86_64_PC32 .Lstr 0xFFFFFFFFFFFFFFFC
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+        leaq    .Lstr(%rip), %rdi
+
+        .section        .rodata.str1.1,"aMS",@progbits,1
+        .Lstr:
+        .asciz "abc\n"
diff --git a/test/ELF/relocatable-non-alloc.s b/test/ELF/relocatable-non-alloc.s
new file mode 100644 (file)
index 0000000..f191580
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/relocatable-non-alloc.s -o %t2.o
+# RUN: ld.lld %t2.o %t2.o -r -o %t3.o
+# RUN: ld.lld %t1.o %t3.o -o %t.o | FileCheck -allow-empty %s
+
+# CHECK-NOT:  has non-ABS reloc
+
+.globl _start
+_start:
diff --git a/test/ELF/relocatable-reloc.s b/test/ELF/relocatable-reloc.s
new file mode 100644 (file)
index 0000000..7c699b9
--- /dev/null
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj %s -o %t.o -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o %t.o -r -o %t2.o
+// RUN: llvm-readobj -r %t2.o | FileCheck %s
+
+.weak foo
+foo:
+.quad foo
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.text {
+// CHECK-NEXT:     0x0 R_X86_64_64 foo 0x0
+// CHECK-NEXT:     0x8 R_X86_64_64 foo 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/relocatable-script.s b/test/ELF/relocatable-script.s
new file mode 100644 (file)
index 0000000..133d61f
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t1.o %s
+# RUN: echo "SECTIONS { .foo : { BYTE(0x0) } }" > %t.script
+# RUN: ld.lld -r %t1.o -script %t.script -o %t2.o
+# RUN: llvm-readobj -sections %t2.o | FileCheck %s
+
+# CHECK:  Name: .foo
diff --git a/test/ELF/relocatable-section-symbol.s b/test/ELF/relocatable-section-symbol.s
new file mode 100644 (file)
index 0000000..57a75ab
--- /dev/null
@@ -0,0 +1,50 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -r -o %t %t.o %t.o
+# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELA %s
+
+# RELA:      Relocations [
+# RELA-NEXT:   Section ({{.*}}) .rela.data {
+# RELA-NEXT:     0x0 R_X86_64_32 .text 0x1
+# RELA-NEXT:     0x4 R_X86_64_32 .text 0x5
+# RELA-NEXT:   }
+# RELA-NEXT: ]
+
+
+# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+# RUN: ld.lld -r -o %t %t.o %t.o
+# RUN: llvm-readobj -r -s -section-data %t | FileCheck --check-prefix=REL %s
+
+
+# REL:      Section {
+# REL:        Index:
+# REL:        Name: .data
+# REL-NEXT:   Type: SHT_PROGBITS
+# REL-NEXT:   Flags [
+# REL-NEXT:     SHF_ALLOC
+# REL-NEXT:     SHF_WRITE
+# REL-NEXT:   ]
+# REL-NEXT:   Address:
+# REL-NEXT:   Offset:
+# REL-NEXT:   Size:
+# REL-NEXT:   Link:
+# REL-NEXT:   Info:
+# REL-NEXT:   AddressAlignment:
+# REL-NEXT:   EntrySize:
+# REL-NEXT:   SectionData (
+# REL-NEXT:     0000: 01000000 05000000                    |
+# REL-NEXT:   )
+# REL-NEXT: }
+
+
+# REL:      Relocations [
+# REL-NEXT:   Section ({{.*}}) .rel.data {
+# REL-NEXT:     0x0 R_386_32 .text 0x0
+# REL-NEXT:     0x4 R_386_32 .text 0x0
+# REL-NEXT:   }
+# REL-NEXT: ]
+
+
+.long 42
+.data
+.long .text + 1
diff --git a/test/ELF/relocatable-sections.s b/test/ELF/relocatable-sections.s
new file mode 100644 (file)
index 0000000..75ede13
--- /dev/null
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld -r %t1.o -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+# CHECK:      .text
+# CHECK-NEXT: .rela.text
+# CHECK: .text._init
+# CHECK-NEXT: .rela.text._init
+# CHECK: .text._fini
+# CHECK-NEXT: .rela.text._fini
+
+.globl _start
+_start:
+ call foo
+ nop
+
+.section .xxx,"a"
+ .quad 0
+
+.section .text._init,"ax"
+ .quad .xxx
+foo:
+ call bar
+ nop
+
+
+.section .text._fini,"ax"
+ .quad .xxx
+bar:
+ nop
diff --git a/test/ELF/relocatable-symbol-name.s b/test/ELF/relocatable-symbol-name.s
new file mode 100644 (file)
index 0000000..d8a85dd
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -r %t.o -o %t
+# RUN: llvm-readobj -t %t | FileCheck %s
+
+# Test that the section symbol has st_name equal to zero. GNU objdump
+# requires this to print relocations against the section.
+
+# CHECK:      Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:  (0)
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type: Section
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
diff --git a/test/ELF/relocatable-symbols.s b/test/ELF/relocatable-symbols.s
new file mode 100644 (file)
index 0000000..79608e7
--- /dev/null
@@ -0,0 +1,201 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -r %t -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+# RUN: llvm-readobj -r %t | FileCheck -check-prefix=RELOC %s
+# RUN: llvm-readobj -symbols -r %tout | FileCheck -check-prefix=SYMBOL %s
+
+# DISASM:      _start:
+# DISASM-NEXT:   0: {{.*}} callq 0
+# DISASM-NEXT:   5: {{.*}} callq 0
+# DISASM-NEXT:   a: {{.*}} callq 0
+# DISASM-NEXT:   f: {{.*}} callq 0
+# DISASM-NEXT:  14: {{.*}} callq 0
+# DISASM-NEXT:  19: {{.*}} callq 0
+# DISASM-NEXT:  1e: {{.*}} callq 0
+# DISASM-NEXT:  23: {{.*}} callq 0
+# DISASM-NEXT:  28: {{.*}} callq 0
+# DISASM-NEXT:  2d: {{.*}} callq 0
+# DISASM-NEXT:  32: {{.*}} callq 0
+# DISASM-NEXT:  37: {{.*}} callq 0
+# DISASM-NEXT: Disassembly of section foo:
+# DISASM-NEXT: foo:
+# DISASM-NEXT:  0: 90 nop
+# DISASM-NEXT:  1: 90 nop
+# DISASM-NEXT:  2: 90 nop
+# DISASM-NEXT: Disassembly of section bar:
+# DISASM-NEXT: bar:
+# DISASM-NEXT:  0: 90 nop
+# DISASM-NEXT:  1: 90 nop
+# DISASM-NEXT:  2: 90 nop
+
+# RELOC:      Relocations [
+# RELOC-NEXT:   Section ({{.*}}) .rela.text {
+# RELOC-NEXT:     0x1 R_X86_64_PC32 __start_foo 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x6 R_X86_64_PC32 __stop_foo 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0xB R_X86_64_PC32 __start_bar 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x10 R_X86_64_PC32 __stop_bar 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x15 R_X86_64_PC32 __start_doo 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x1A R_X86_64_PC32 __stop_doo 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x1F R_X86_64_PC32 __preinit_array_start 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x24 R_X86_64_PC32 __preinit_array_end 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x29 R_X86_64_PC32 __init_array_start 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x2E R_X86_64_PC32 __init_array_end 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x33 R_X86_64_PC32 __fini_array_start 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:     0x38 R_X86_64_PC32 __fini_array_end 0xFFFFFFFFFFFFFFFC
+# RELOC-NEXT:   }
+# RELOC-NEXT: ]
+
+# SYMBOL:      Relocations [
+# SYMBOL-NEXT:  Section ({{.*}}) .rela.text {
+# SYMBOL-NEXT:     0x1 R_X86_64_PC32 __start_foo 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x6 R_X86_64_PC32 __stop_foo 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0xB R_X86_64_PC32 __start_bar 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x10 R_X86_64_PC32 __stop_bar 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x15 R_X86_64_PC32 __start_doo 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x1A R_X86_64_PC32 __stop_doo 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x1F R_X86_64_PC32 __preinit_array_start 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x24 R_X86_64_PC32 __preinit_array_end 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x29 R_X86_64_PC32 __init_array_start 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x2E R_X86_64_PC32 __init_array_end 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x33 R_X86_64_PC32 __fini_array_start 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:     0x38 R_X86_64_PC32 __fini_array_end 0xFFFFFFFFFFFFFFFC
+# SYMBOL-NEXT:   }
+# SYMBOL-NEXT: ]
+# SYMBOL:      Symbol {
+# SYMBOL:        Name: __fini_array_end
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __fini_array_start
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __init_array_end
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __init_array_start
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __preinit_array_end
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __preinit_array_start
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __start_bar
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __start_doo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __start_foo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __stop_bar
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __stop_doo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+# SYMBOL-NEXT: Symbol {
+# SYMBOL-NEXT:   Name: __stop_foo
+# SYMBOL-NEXT:   Value: 0x0
+# SYMBOL-NEXT:   Size: 0
+# SYMBOL-NEXT:   Binding: Global
+# SYMBOL-NEXT:   Type: None
+# SYMBOL-NEXT:   Other: 0
+# SYMBOL-NEXT:   Section: Undefined
+# SYMBOL-NEXT: }
+
+.global _start
+.text
+_start:
+ call __start_foo
+ call __stop_foo
+
+ call __start_bar
+ call __stop_bar
+
+ call __start_doo
+ call __stop_doo
+
+ call __preinit_array_start
+ call __preinit_array_end
+ call __init_array_start
+ call __init_array_end
+ call __fini_array_start
+ call __fini_array_end
+
+.section foo,"ax"
+ nop
+ nop
+ nop
+
+.section bar,"ax"
+ nop
+ nop
+ nop
diff --git a/test/ELF/relocatable-tls.s b/test/ELF/relocatable-tls.s
new file mode 100644 (file)
index 0000000..ff04dd2
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:   %S/Inputs/relocatable-tls.s -o %t2.o
+
+# RUN: ld.lld -r %t2.o -o %t3.r
+# RUN: llvm-objdump -t %t3.r | FileCheck --check-prefix=RELOCATABLE %s
+# RELOCATABLE: SYMBOL TABLE:
+# RELOCATABLE: 0000000000000000 *UND* 00000000 __tls_get_addr
+
+# RUN: ld.lld -shared %t2.o %t3.r -o %t4.out
+# RUN: llvm-objdump -t %t4.out | FileCheck --check-prefix=DSO %s
+# DSO: SYMBOL TABLE:
+# DSO: 0000000000000000 *UND* 00000000 __tls_get_addr
+
+callq __tls_get_addr@PLT
diff --git a/test/ELF/relocatable-visibility.s b/test/ELF/relocatable-visibility.s
new file mode 100644 (file)
index 0000000..7cc7da3
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -r %t.o -o %t1
+# RUN: llvm-readobj -t %t1 | FileCheck --check-prefix=RELOCATABLE %s
+
+# RELOCATABLE:      Name: foo
+# RELOCATABLE-NEXT: Value: 0x0
+# RELOCATABLE-NEXT: Size: 0
+# RELOCATABLE-NEXT: Binding: Global
+# RELOCATABLE-NEXT: Type: None
+# RELOCATABLE-NEXT: Other [
+# RELOCATABLE-NEXT:   STV_HIDDEN
+# RELOCATABLE-NEXT: ]
+# RELOCATABLE-NEXT: Section: Undefined
+
+.global _start
+_start:
+ callq foo
+ .hidden foo
diff --git a/test/ELF/relocatable.s b/test/ELF/relocatable.s
new file mode 100644 (file)
index 0000000..00572d0
--- /dev/null
@@ -0,0 +1,120 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable2.s -o %t3.o
+# RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s
+
+## Test --relocatable alias
+# RUN: ld.lld --relocatable %t1.o %t2.o %t3.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s
+
+## Verify that we can use our relocation output as input to produce executable
+# RUN: ld.lld -e main %t -o %texec
+# RUN: llvm-readobj -file-headers %texec | FileCheck -check-prefix=CHECKEXE %s
+
+# CHECK:       ElfHeader {
+# CHECK-NEXT:  Ident {
+# CHECK-NEXT:    Magic: (7F 45 4C 46)
+# CHECK-NEXT:    Class: 64-bit
+# CHECK-NEXT:    DataEncoding: LittleEndian
+# CHECK-NEXT:    FileVersion: 1
+# CHECK-NEXT:    OS/ABI: SystemV
+# CHECK-NEXT:    ABIVersion: 0
+# CHECK-NEXT:    Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Type: Relocatable
+# CHECK-NEXT:  Machine: EM_X86_64
+# CHECK-NEXT:  Version: 1
+# CHECK-NEXT:  Entry: 0x0
+# CHECK-NEXT:  ProgramHeaderOffset: 0x0
+# CHECK-NEXT:  SectionHeaderOffset:
+# CHECK-NEXT:  Flags [
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  HeaderSize: 64
+# CHECK-NEXT:  ProgramHeaderEntrySize: 0
+# CHECK-NEXT:  ProgramHeaderCount: 0
+# CHECK-NEXT:  SectionHeaderEntrySize: 64
+# CHECK-NEXT:  SectionHeaderCount: 7
+# CHECK-NEXT:  StringTableSectionIndex: 5
+# CHECK-NEXT:  }
+
+# CHECK:       Relocations [
+# CHECK-NEXT:  Section ({{.*}}) .rela.text {
+# CHECK-NEXT:    0x3 R_X86_64_32S x 0x0
+# CHECK-NEXT:    0xE R_X86_64_32S y 0x0
+# CHECK-NEXT:    0x23 R_X86_64_32S xx 0x0
+# CHECK-NEXT:    0x2E R_X86_64_32S yy 0x0
+# CHECK-NEXT:    0x43 R_X86_64_32S xxx 0x0
+# CHECK-NEXT:    0x4E R_X86_64_32S yyy 0x0
+# CHECK-NEXT:  }
+
+# CHECKTEXT:      Disassembly of section .text:
+# CHECKTEXT-NEXT: main:
+# CHECKTEXT-NEXT: 0: c7 04 25 00 00 00 00 05 00 00 00 movl $5, 0
+# CHECKTEXT-NEXT: b: c7 04 25 00 00 00 00 07 00 00 00 movl $7, 0
+# CHECKTEXT:      foo:
+# CHECKTEXT-NEXT: 20: c7 04 25 00 00 00 00 01 00 00 00 movl $1, 0
+# CHECKTEXT-NEXT: 2b: c7 04 25 00 00 00 00 02 00 00 00 movl $2, 0
+# CHECKTEXT:      bar:
+# CHECKTEXT-NEXT: 40: c7 04 25 00 00 00 00 08 00 00 00 movl $8, 0
+# CHECKTEXT-NEXT: 4b: c7 04 25 00 00 00 00 09 00 00 00 movl $9, 0
+
+# CHECKEXE:       Format: ELF64-x86-64
+# CHECKEXE-NEXT:  Arch: x86_64
+# CHECKEXE-NEXT:  AddressSize: 64bit
+# CHECKEXE-NEXT:  LoadName:
+# CHECKEXE-NEXT:  ElfHeader {
+# CHECKEXE-NEXT:    Ident {
+# CHECKEXE-NEXT:      Magic: (7F 45 4C 46)
+# CHECKEXE-NEXT:      Class: 64-bit
+# CHECKEXE-NEXT:      DataEncoding: LittleEndian
+# CHECKEXE-NEXT:      FileVersion: 1
+# CHECKEXE-NEXT:      OS/ABI: SystemV (0x0)
+# CHECKEXE-NEXT:      ABIVersion: 0
+# CHECKEXE-NEXT:      Unused: (00 00 00 00 00 00 00)
+# CHECKEXE-NEXT:    }
+# CHECKEXE-NEXT:    Type: Executable
+# CHECKEXE-NEXT:    Machine: EM_X86_64
+# CHECKEXE-NEXT:    Version: 1
+# CHECKEXE-NEXT:    Entry: 0x201000
+# CHECKEXE-NEXT:    ProgramHeaderOffset: 0x40
+# CHECKEXE-NEXT:    SectionHeaderOffset: 0x11F8
+# CHECKEXE-NEXT:    Flags [
+# CHECKEXE-NEXT:    ]
+# CHECKEXE-NEXT:    HeaderSize: 64
+# CHECKEXE-NEXT:    ProgramHeaderEntrySize: 56
+# CHECKEXE-NEXT:    ProgramHeaderCount: 5
+# CHECKEXE-NEXT:    SectionHeaderEntrySize: 64
+# CHECKEXE-NEXT:    SectionHeaderCount: 7
+# CHECKEXE-NEXT:    StringTableSectionIndex: 5
+# CHECKEXE-NEXT:  }
+
+.text
+.type x,@object
+.bss
+.globl x
+.align 4
+x:
+.long 0
+.size x, 4
+.type y,@object
+.globl y
+.align 4
+y:
+.long 0
+.size y, 4
+
+.text
+.globl main
+.align 16, 0x90
+.type main,@function
+main:
+movl $5, x
+movl $7, y
+
+blah:
+goo:
+abs = 42
diff --git a/test/ELF/relocation-absolute.s b/test/ELF/relocation-absolute.s
new file mode 100644 (file)
index 0000000..20d54ec
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/abs.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %tabs %t -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+  movl $abs, %edx
+
+//CHECK:      start:
+//CHECK-NEXT: movl     $66, %edx
diff --git a/test/ELF/relocation-common.s b/test/ELF/relocation-common.s
new file mode 100644 (file)
index 0000000..28276bf
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-objdump -t -d %tout | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+  movl $1, sym1(%rip)
+
+.global sym1
+.comm sym1,4,4
+
+// CHECK: 201000: {{.*}} movl    $1, 4086(%rip)
+// CHECK: 0000000000202000 g       .bss            00000004 sym1
diff --git a/test/ELF/relocation-copy-alias.s b/test/ELF/relocation-copy-alias.s
new file mode 100644 (file)
index 0000000..15712e3
--- /dev/null
@@ -0,0 +1,67 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-alias.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj --dyn-symbols -r --expand-relocs %t3 | FileCheck %s
+
+.global _start
+_start:
+movl $5, a1
+movl $5, b1
+movl $5, b2
+
+// CHECK:      .rela.dyn {
+// CHECK-NEXT:   Relocation {
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Type: R_X86_64_COPY
+// CHECK-NEXT:     Symbol: a1
+// CHECK-NEXT:     Addend: 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Relocation {
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Type: R_X86_64_COPY
+// CHECK-NEXT:     Symbol: b1
+// CHECK-NEXT:     Addend: 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
+
+// CHECK:      Name: a1
+// CHECK-NEXT: Value: [[A:.*]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Global (0x1)
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss (0x7)
+
+// CHECK:      Name: b1
+// CHECK-NEXT: Value: [[B:.*]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: b2
+// CHECK-NEXT: Value: [[B]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: a2
+// CHECK-NEXT: Value: [[A]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Weak
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CHECK:      Name: b3
+// CHECK-NEXT: Value: [[B]]
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Binding: Weak
+// CHECK-NEXT: Type: Object (0x1)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
diff --git a/test/ELF/relocation-copy-align-common.s b/test/ELF/relocation-copy-align-common.s
new file mode 100644 (file)
index 0000000..a94c208
--- /dev/null
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
+# RUN:   %p/Inputs/relocation-copy-align-common.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t3
+# RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s
+
+# CHECK:      Section {
+# CHECK:        Index:
+# CHECK:        Name: .bss
+# CHECK-NEXT:   Type: SHT_NOBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_WRITE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x203000
+# CHECK-NEXT:   Offset: 0x20B0
+# CHECK-NEXT:   Size: 16
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 8
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT: }
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section {{.*}} .rela.dyn {
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       Offset: 0x203008
+# CHECK-NEXT:       Type: R_X86_64_COPY
+# CHECK-NEXT:       Symbol: foo
+# CHECK-NEXT:       Addend: 0x0
+# CHECK-NEXT:     }
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+.comm sym1,4,4
+movl $5, foo
diff --git a/test/ELF/relocation-copy-align.s b/test/ELF/relocation-copy-align.s
new file mode 100644 (file)
index 0000000..07ae663
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-align.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s
+
+.global _start
+_start:
+movl $5, x
+
+// CHECK:    Name: .bss
+// CHECK-NEXT:    Type: SHT_NOBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_WRITE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address:
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size: 4
+// CHECK-NEXT:    Link:
+// CHECK-NEXT:    Info:
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize:
+
+// CHECK:      Relocation {
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   Type: R_X86_64_COPY
+// CHECK-NEXT:   Symbol: x
+// CHECK-NEXT:   Addend: 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/relocation-copy-flags.s b/test/ELF/relocation-copy-flags.s
new file mode 100644 (file)
index 0000000..4d97e3d
--- /dev/null
@@ -0,0 +1,73 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -s -section-data -r %t.exe | FileCheck %s
+
+        .global _start
+_start:
+        .quad x
+
+        .section foo
+        .quad y
+
+        .section bar, "aw"
+        .quad z
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x201000
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00402000
+// CHECK-NEXT: )
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x202000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset: 0x30B0
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     0x204000 R_X86_64_COPY x 0x0
+// CHECK-NEXT:     0x202000 R_X86_64_64 z 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/relocation-copy-i686.s b/test/ELF/relocation-copy-i686.s
new file mode 100644 (file)
index 0000000..f9ee32e
--- /dev/null
@@ -0,0 +1,63 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld -e main %t.o %t.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s
+
+.text
+.globl main
+.align 16, 0x90
+.type main,@function
+main:
+movl $5, x
+movl $7, y
+movl $9, z
+
+// CHECK:      Name: .bss
+// CHECK-NEXT:  Type: SHT_NOBITS
+// CHECK-NEXT:  Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: 0x13000
+// CHECK-NEXT:  Offset:
+// CHECK-NEXT:  Size: 24
+// CHECK-NEXT:  Link: 0
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 16
+// CHECK-NEXT:  EntrySize: 0
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rel.dyn {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_386_COPY
+// CHECK-NEXT:       Symbol: x
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_386_COPY
+// CHECK-NEXT:       Symbol: y
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_386_COPY
+// CHECK-NEXT:       Symbol: z
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// 77824 = 0x13000
+// 16 is alignment here
+// 77840 = 0x13000 + 16
+// 77844 = 0x13000 + 16 + 4
+// CODE: Disassembly of section .text:
+// CODE-NEXT: main:
+// CODE-NEXT: 11000: c7 05 00 30 01 00 05 00 00 00 movl $5, 77824
+// CODE-NEXT: 1100a: c7 05 10 30 01 00 07 00 00 00 movl $7, 77840
+// CODE-NEXT: 11014: c7 05 14 30 01 00 09 00 00 00 movl $9, 77844
diff --git a/test/ELF/relocation-copy-relro.s b/test/ELF/relocation-copy-relro.s
new file mode 100644 (file)
index 0000000..1684c40
--- /dev/null
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-relro.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj -program-headers -s -r %t3 | FileCheck %s
+
+// CHECK:        Name: .bss.rel.ro (48)
+// CHECK-NEXT:   Type: SHT_NOBITS (0x8)
+// CHECK-NEXT:   Flags [ (0x3)
+// CHECK-NEXT:     SHF_ALLOC (0x2)
+// CHECK-NEXT:     SHF_WRITE (0x1)
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: 0x2020B0
+// CHECK-NEXT:   Offset: 0x20B0
+// CHECK-NEXT:   Size: 8
+
+// CHECK: 0x2020B0 R_X86_64_COPY a 0x0
+// CHECK: 0x2020B4 R_X86_64_COPY b 0x0
+
+// CHECK:      Type: PT_GNU_RELRO (0x6474E552)
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: VirtualAddress: 0x202000
+// CHECK-NEXT: PhysicalAddress: 0x202000
+// CHECK-NEXT: FileSize: 176
+// CHECK-NEXT: MemSize: 4096
+
+.text
+.global _start
+_start:
+movl $1, a
+movl $2, b
diff --git a/test/ELF/relocation-copy.s b/test/ELF/relocation-copy.s
new file mode 100644 (file)
index 0000000..9a3254f
--- /dev/null
@@ -0,0 +1,67 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s
+
+.text
+.global _start
+_start:
+movl $5, x
+movl $7, y
+movl $9, z
+movl $x, %edx
+movl $y, %edx
+movl $z, %edx
+
+// CHECK:      Name: .bss
+// CHECK-NEXT:  Type: SHT_NOBITS (0x8)
+// CHECK-NEXT:  Flags [ (0x3)
+// CHECK-NEXT:   SHF_ALLOC (0x2)
+// CHECK-NEXT:   SHF_WRITE (0x1)
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Address: 0x203000
+// CHECK-NEXT:  Offset:
+// CHECK-NEXT:  Size: 24
+// CHECK-NEXT:  Link: 0
+// CHECK-NEXT:  Info: 0
+// CHECK-NEXT:  AddressAlignment: 16
+// CHECK-NEXT:  EntrySize: 0
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_X86_64_COPY
+// CHECK-NEXT:       Symbol: x
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_X86_64_COPY
+// CHECK-NEXT:       Symbol: y
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset:
+// CHECK-NEXT:       Type: R_X86_64_COPY
+// CHECK-NEXT:       Symbol: z
+// CHECK-NEXT:       Addend: 0x0
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// 2109440 = 0x203000
+// 16 is alignment here
+// 2109456 = 0x203000 + 16
+// 2109460 = 0x203000 + 16 + 4
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT: 201000: {{.*}} movl $5, 2109440
+// CODE-NEXT: 20100b: {{.*}} movl $7, 2109456
+// CODE-NEXT: 201016: {{.*}} movl $9, 2109460
+// CODE-NEXT: 201021: {{.*}} movl $2109440, %edx
+// CODE-NEXT: 201026: {{.*}} movl $2109456, %edx
+// CODE-NEXT: 20102b: {{.*}} movl $2109460, %edx
diff --git a/test/ELF/relocation-dtrace.test b/test/ELF/relocation-dtrace.test
new file mode 100644 (file)
index 0000000..ef2cc49
--- /dev/null
@@ -0,0 +1,24 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+
+# Test that we can handle R_X86_64_NONE as produced by dtrace.
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_FREEBSD
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          ''
+        Type:            R_X86_64_NONE
diff --git a/test/ELF/relocation-group.test b/test/ELF/relocation-group.test
new file mode 100644 (file)
index 0000000..0820ff8
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o %t.o -o %t -r
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK:     Name: .text.foo
+# CHECK:     Name: .rela.text.foo
+
+## YAML below corresponds to following asm code:
+## .section .text,"axG",@progbits,foo,comdat
+## .quad bar
+## gas 2.27 does not include .rela.text to group in that case:
+## COMDAT group section [    1] `.group' [foo] contains 1 sections:
+##   [Index]    Name
+##   [    5]   .text
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    Info:            foo
+    Members:
+      - SectionOrType:    GRP_COMDAT
+      - SectionOrType:    .text.foo
+  - Name:            .text.foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+  - Name:            .rela.text.foo
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    Info:            .text.foo
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          foo
+        Type:            R_X86_64_64
+Symbols:
+  Global:
+    - Name:            foo
diff --git a/test/ELF/relocation-i686.s b/test/ELF/relocation-i686.s
new file mode 100644 (file)
index 0000000..4bb55d9
--- /dev/null
@@ -0,0 +1,96 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t %t2.so -o %t2
+// RUN: llvm-readobj -s %t2 | FileCheck --check-prefix=ADDR %s
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+
+.section       .R_386_32,"ax",@progbits
+.global R_386_32
+R_386_32:
+  movl $R_386_32 + 1, %edx
+
+
+.section       .R_386_PC32,"ax",@progbits,unique,1
+.global R_386_PC32
+R_386_PC32:
+  call R_386_PC32_2
+
+.section       .R_386_PC32,"ax",@progbits,unique,2
+.zero 4
+R_386_PC32_2:
+  nop
+
+// CHECK: Disassembly of section .R_386_32:
+// CHECK-NEXT: R_386_32:
+// CHECK-NEXT:  11000: {{.*}} movl $69633, %edx
+
+// CHECK: Disassembly of section .R_386_PC32:
+// CHECK-NEXT: R_386_PC32:
+// CHECK-NEXT:   11005:  e8 04 00 00 00  calll 4
+
+// CHECK:      R_386_PC32_2:
+// CHECK-NEXT:   1100e:  90  nop
+
+// Create a .got
+movl bar@GOT, %eax
+
+// ADDR:      Name: .plt
+// ADDR-NEXT: Type: SHT_PROGBITS
+// ADDR-NEXT: Flags [
+// ADDR-NEXT:   SHF_ALLOC
+// ADDR-NEXT:   SHF_EXECINSTR
+// ADDR-NEXT: ]
+// ADDR-NEXT: Address: 0x11040
+// ADDR-NEXT: Offset: 0x1040
+// ADDR-NEXT: Size: 32
+
+// ADDR:      Name: .got (
+// ADDR-NEXT: Type: SHT_PROGBITS
+// ADDR-NEXT: Flags [
+// ADDR-NEXT:   SHF_ALLOC
+// ADDR-NEXT:   SHF_WRITE
+// ADDR-NEXT: ]
+// ADDR-NEXT: Address: 0x13078
+// ADDR-NEXT: Offset:
+// ADDR-NEXT: Size: 8
+
+.section .R_386_GOTPC,"ax",@progbits
+R_386_GOTPC:
+ movl $_GLOBAL_OFFSET_TABLE_, %eax
+
+// 0x12078 + 8 - 0x11014 = 4204
+
+// CHECK:      Disassembly of section .R_386_GOTPC:
+// CHECK-NEXT: R_386_GOTPC:
+// CHECK-NEXT:   11014:  {{.*}} movl  $8300, %eax
+
+.section .dynamic_reloc, "ax",@progbits
+ call bar
+// addr(.plt) + 16 - (0x11019 + 5) = 50
+// CHECK:      Disassembly of section .dynamic_reloc:
+// CHECK-NEXT: .dynamic_reloc:
+// CHECK-NEXT:   11019:  e8 32 00 00 00 calll 50
+
+.section .R_386_GOT32,"ax",@progbits
+.global R_386_GOT32
+R_386_GOT32:
+ movl bar@GOT, %eax
+ movl zed@GOT, %eax
+ movl bar+8@GOT, %eax
+ movl zed+4@GOT, %eax
+
+// 4294967288 = 0xFFFFFFF8 = got[0](0x12070) - .got(0x12070) - sizeof(.got)(8)
+// 4294967292 = 0xFFFFFFFC = got[1](0x12074) - .got(0x12070) - sizeof(.got)(8)
+// 0xFFFFFFF8 + 8 = 0
+// 0xFFFFFFFC + 4 = 0
+// CHECK:      Disassembly of section .R_386_GOT32:
+// CHECK-NEXT: R_386_GOT32:
+// CHECK-NEXT: 1101e: a1 f8 ff ff ff movl 4294967288, %eax
+// CHECK-NEXT: 11023: a1 fc ff ff ff movl 4294967292, %eax
+// CHECK-NEXT: 11028: a1 00 00 00 00 movl 0, %eax
+// CHECK-NEXT: 1102d: a1 00 00 00 00 movl 0, %eax
diff --git a/test/ELF/relocation-in-merge.s b/test/ELF/relocation-in-merge.s
new file mode 100644 (file)
index 0000000..b37eff3
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t -shared
+// RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+// Test that we accept this by just not merging the section.
+// CHECK:  .foo          00000008
+
+bar:
+        .section       .foo,"aM",@progbits,8
+        .long bar - .
+        .long bar - .
diff --git a/test/ELF/relocation-local.s b/test/ELF/relocation-local.s
new file mode 100644 (file)
index 0000000..8173dac
--- /dev/null
@@ -0,0 +1,38 @@
+// Test that relocation of local symbols is working.
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -s -d %t2 | FileCheck %s
+// REQUIRES: x86
+
+
+.global _start
+_start:
+  call lulz
+
+.zero 4
+lulz:
+
+.section       .text2,"ax",@progbits
+R_X86_64_32:
+  movl $R_X86_64_32, %edx
+
+// FIXME: this would be far more self evident if llvm-objdump printed
+// constants in hex.
+// CHECK: Disassembly of section .text2:
+// CHECK-NEXT: R_X86_64_32:
+// CHECK-NEXT:  201009: {{.*}} movl $2101257, %edx
+
+.section .R_X86_64_32S,"ax",@progbits
+R_X86_64_32S:
+  movq lulz - 0x100000, %rdx
+
+// CHECK: Disassembly of section .R_X86_64_32S:
+// CHECK-NEXT: R_X86_64_32S:
+// CHECK-NEXT:  {{.*}}: {{.*}} movq 1052681, %rdx
+
+.section .R_X86_64_64,"a",@progbits
+R_X86_64_64:
+ .quad R_X86_64_64
+
+// CHECK:      Contents of section .R_X86_64_64:
+// CHECK-NEXT:   200120 20012000 00000000
diff --git a/test/ELF/relocation-nocopy.s b/test/ELF/relocation-nocopy.s
new file mode 100644 (file)
index 0000000..533277d
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: not ld.lld -z nocopyreloc %t.o %t.so -o %t3 2>&1 | FileCheck %s
+
+// CHECK: unresolvable relocation R_X86_64_32S against symbol 'x'
+// CHECK: unresolvable relocation R_X86_64_32S against symbol 'y'
+// CHECK: unresolvable relocation R_X86_64_32S against symbol 'z'
+
+.text
+.global _start
+_start:
+movl $5, x
+movl $7, y
+movl $9, z
+movl $x, %edx
+movl $y, %edx
+movl $z, %edx
diff --git a/test/ELF/relocation-non-alloc.s b/test/ELF/relocation-non-alloc.s
new file mode 100644 (file)
index 0000000..1ad15a4
--- /dev/null
@@ -0,0 +1,60 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t2 -shared
+// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck %s
+
+// CHECK:      Name: .data
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+// CHECK-NEXT: Offset: 0x1000
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000 00000000 00000000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00100000 00000000 00100000 00000000
+// CHECK-NEXT:   0010: 00100000 00000000 00100000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.}}) .rela.dyn {
+// CHECK-NEXT:     0x1000 R_X86_64_RELATIVE - 0x1000
+// CHECK-NEXT:     0x1008 R_X86_64_64 zed 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.data
+        .global zed
+zed:
+bar:
+        .quad bar
+        .quad zed
+
+        .section foo
+        .quad bar
+        .quad zed
+
+        .section foo
+        .quad bar
+        .quad zed
diff --git a/test/ELF/relocation-none-aarch64.test b/test/ELF/relocation-none-aarch64.test
new file mode 100644 (file)
index 0000000..dd67c8c
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: aarch64
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t.out
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_AARCH64
+Sections:
+  - Type:            SHT_PROGBITS
+    Name:            .text
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content:         "00000000"
+  - Type:            SHT_RELA
+    Name:            .rela.text
+    Link:            .symtab
+    Info:            .text
+    Relocations:
+      - Offset:          0
+        Symbol:          ''
+        Type:            R_AARCH64_NONE
diff --git a/test/ELF/relocation-none-i686.test b/test/ELF/relocation-none-i686.test
new file mode 100644 (file)
index 0000000..d8eed8f
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t.out
+
+# Test that we can handle R_386_NONE.
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_386
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+  - Name:            .rel.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          ''
+        Type:            R_386_NONE
diff --git a/test/ELF/relocation-past-merge-end.s b/test/ELF/relocation-past-merge-end.s
new file mode 100644 (file)
index 0000000..d08bde7
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+// CHECK: relocation-past-merge-end.s.tmp.o:(.foo): entry is past the end of the section
+
+.data
+.long .foo + 10
+.section       .foo,"aM",@progbits,4
+.quad 0
diff --git a/test/ELF/relocation-relative-absolute.s b/test/ELF/relocation-relative-absolute.s
new file mode 100644 (file)
index 0000000..2a343fd
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %tinput1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
+# RUN:   %S/Inputs/relocation-relative-absolute.s -o %tinput2.o
+# RUN: not ld.lld %tinput1.o %tinput2.o -o %t -pie 2>&1 | FileCheck %s
+
+.globl _start
+_start:
+
+# CHECK:      error: relocation R_X86_64_PLT32 cannot refer to absolute symbol: answer
+# CHECK-NEXT: >>> defined in {{.*}}input2.o
+# CHECK-NEXT: >>> referenced by {{.*}}o:(.text+0x1)
+
+call answer@PLT
diff --git a/test/ELF/relocation-relative-synthetic.s b/test/ELF/relocation-relative-synthetic.s
new file mode 100644 (file)
index 0000000..f4d449b
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+call __init_array_start@PLT
diff --git a/test/ELF/relocation-relative-weak.s b/test/ELF/relocation-relative-weak.s
new file mode 100644 (file)
index 0000000..c525012
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
+
+# CHECK:      Dynamic Relocations {
+# CHECK-NEXT: }
+
+.globl _start
+_start:
+
+.globl w
+.weak w
+call w@PLT
diff --git a/test/ELF/relocation-shared.s b/test/ELF/relocation-shared.s
new file mode 100644 (file)
index 0000000..4fba7a5
--- /dev/null
@@ -0,0 +1,36 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -shared -o %t.so
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1C8
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 380E0000 00000000
+//                     0x1000 - 0x1C8 = 0xE38
+// CHECK-NEXT: )
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
+
+bar:
+        .section foo,"a",@progbits
+        .quad bar - .
diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s
new file mode 100644 (file)
index 0000000..cea9e64
--- /dev/null
@@ -0,0 +1,78 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocation-size-shared.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld %t.o %tso -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOCSHARED %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// RELOCSHARED:       Relocations [
+// RELOCSHARED-NEXT:  Section ({{.*}}) .rela.dyn {
+// RELOCSHARED-NEXT:    0x201018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x201020 R_X86_64_SIZE64 fooshared 0x0
+// RELOCSHARED-NEXT:    0x201028 R_X86_64_SIZE64 fooshared 0x1
+// RELOCSHARED-NEXT:    0x201048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x20104F R_X86_64_SIZE32 fooshared 0x0
+// RELOCSHARED-NEXT:    0x201056 R_X86_64_SIZE32 fooshared 0x1
+// RELOCSHARED-NEXT:  }
+// RELOCSHARED-NEXT:]
+
+// DISASM:      Disassembly of section test
+// DISASM:      _data:
+// DISASM-NEXT: 201000: 19 00
+// DISASM-NEXT: 201002: 00 00
+// DISASM-NEXT: 201004: 00 00
+// DISASM-NEXT: 201006: 00 00
+// DISASM-NEXT: 201008: 1a 00
+// DISASM-NEXT: 20100a: 00 00
+// DISASM-NEXT: 20100c: 00 00
+// DISASM-NEXT: 20100e: 00 00
+// DISASM-NEXT: 201010: 1b 00
+// DISASM-NEXT: 201012: 00 00
+// DISASM-NEXT: 201014: 00 00
+// DISASM-NEXT: 201016: 00 00
+// DISASM-NEXT: 201018: 00 00
+// DISASM-NEXT: 20101a: 00 00
+// DISASM-NEXT: 20101c: 00 00
+// DISASM-NEXT: 20101e: 00 00
+// DISASM-NEXT: 201020: 00 00
+// DISASM-NEXT: 201022: 00 00
+// DISASM-NEXT: 201024: 00 00
+// DISASM-NEXT: 201026: 00 00
+// DISASM-NEXT: 201028: 00 00
+// DISASM-NEXT: 20102a: 00 00
+// DISASM-NEXT: 20102c: 00 00
+// DISASM-NEXT: 20102e: 00 00
+// DISASM:      _start:
+// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax
+// DISASM-NEXT: 201045: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASM-NEXT: 20104c: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASM-NEXT: 201053: 8b 04 25 00 00 00 00 movl 0, %eax
+
+.data
+.global foo
+.type foo,%object
+.size foo,26
+foo:
+.zero 26
+
+.section test, "awx"
+_data:
+  // R_X86_64_SIZE64:
+  .quad foo@SIZE-1
+  .quad foo@SIZE
+  .quad foo@SIZE+1
+  .quad fooshared@SIZE-1
+  .quad fooshared@SIZE
+  .quad fooshared@SIZE+1
+
+.globl _start
+_start:
+  // R_X86_64_SIZE32:
+  movl foo@SIZE-1,%eax
+  movl foo@SIZE,%eax
+  movl foo@SIZE+1,%eax
+  movl fooshared@SIZE-1,%eax
+  movl fooshared@SIZE,%eax
+  movl fooshared@SIZE+1,%eax
diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s
new file mode 100644 (file)
index 0000000..419b8a1
--- /dev/null
@@ -0,0 +1,123 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+// RUN: ld.lld -shared %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOCSHARED %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASMSHARED %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section test:
+// DISASM-NEXT: _data:
+// DISASM-NEXT: 201000: 19 00
+// DISASM-NEXT: 201002: 00 00
+// DISASM-NEXT: 201004: 00 00
+// DISASM-NEXT: 201006: 00 00
+// DISASM-NEXT: 201008: 1a 00
+// DISASM-NEXT: 20100a: 00 00
+// DISASM-NEXT: 20100c: 00 00
+// DISASM-NEXT: 20100e: 00 00
+// DISASM-NEXT: 201010: 1b 00
+// DISASM-NEXT: 201012: 00 00
+// DISASM-NEXT: 201014: 00 00
+// DISASM-NEXT: 201016: 00 00
+// DISASM-NEXT: 201018: 19 00
+// DISASM-NEXT: 20101a: 00 00
+// DISASM-NEXT: 20101c: 00 00
+// DISASM-NEXT: 20101e: 00 00
+// DISASM-NEXT: 201020: 1a 00
+// DISASM-NEXT: 201022: 00 00
+// DISASM-NEXT: 201024: 00 00
+// DISASM-NEXT: 201026: 00 00
+// DISASM-NEXT: 201028: 1b 00
+// DISASM-NEXT: 20102a: 00 00
+// DISASM-NEXT: 20102c: 00 00
+// DISASM-NEXT: 20102e: 00 00
+// DISASM:      _start:
+// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax
+// DISASM-NEXT: 201045: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASM-NEXT: 20104c: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASM-NEXT: 201053: 8b 04 25 1b 00 00 00 movl 27, %eax
+
+// RELOCSHARED:      Relocations [
+// RELOCSHARED-NEXT: Section ({{.*}}) .rela.dyn {
+// RELOCSHARED-NEXT:    0x1000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x1008 R_X86_64_SIZE64 foo 0x0
+// RELOCSHARED-NEXT:    0x1010 R_X86_64_SIZE64 foo 0x1
+// RELOCSHARED-NEXT:    0x1033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF
+// RELOCSHARED-NEXT:    0x103A R_X86_64_SIZE32 foo 0x0
+// RELOCSHARED-NEXT:    0x1041 R_X86_64_SIZE32 foo 0x1
+// RELOCSHARED-NEXT:  }
+// RELOCSHARED-NEXT: ]
+
+// DISASMSHARED:      Disassembly of section test:
+// DISASMSHARED-NEXT: _data:
+// DISASMSHARED-NEXT: 1000: 00 00
+// DISASMSHARED-NEXT: 1002: 00 00
+// DISASMSHARED-NEXT: 1004: 00 00
+// DISASMSHARED-NEXT: 1006: 00 00
+// DISASMSHARED-NEXT: 1008: 00 00
+// DISASMSHARED-NEXT: 100a: 00 00
+// DISASMSHARED-NEXT: 100c: 00 00
+// DISASMSHARED-NEXT: 100e: 00 00
+// DISASMSHARED-NEXT: 1010: 00 00
+// DISASMSHARED-NEXT: 1012: 00 00
+// DISASMSHARED-NEXT: 1014: 00 00
+// DISASMSHARED-NEXT: 1016: 00 00
+// DISASMSHARED-NEXT: 1018: 19 00
+// DISASMSHARED-NEXT: 101a: 00 00
+// DISASMSHARED-NEXT: 101c: 00 00
+// DISASMSHARED-NEXT: 101e: 00 00
+// DISASMSHARED-NEXT: 1020: 1a 00
+// DISASMSHARED-NEXT: 1022: 00 00
+// DISASMSHARED-NEXT: 1024: 00 00
+// DISASMSHARED-NEXT: 1026: 00 00
+// DISASMSHARED-NEXT: 1028: 1b 00
+// DISASMSHARED-NEXT: 102a: 00 00
+// DISASMSHARED-NEXT: 102c: 00 00
+// DISASMSHARED-NEXT: 102e: 00 00
+// DISASMSHARED:      _start:
+// DISASMSHARED-NEXT: 1030: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASMSHARED-NEXT: 1037: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASMSHARED-NEXT: 103e: 8b 04 25 00 00 00 00 movl 0, %eax
+// DISASMSHARED-NEXT: 1045: 8b 04 25 19 00 00 00 movl 25, %eax
+// DISASMSHARED-NEXT: 104c: 8b 04 25 1a 00 00 00 movl 26, %eax
+// DISASMSHARED-NEXT: 1053: 8b 04 25 1b 00 00 00 movl 27, %eax
+
+.data
+.global foo
+.type foo,%object
+.size foo,26
+foo:
+.zero 26
+
+.data
+.global foohidden
+.hidden foohidden
+.type foohidden,%object
+.size foohidden,26
+foohidden:
+.zero 26
+
+.section test,"axw"
+_data:
+  // R_X86_64_SIZE64:
+  .quad foo@SIZE-1
+  .quad foo@SIZE
+  .quad foo@SIZE+1
+  .quad foohidden@SIZE-1
+  .quad foohidden@SIZE
+  .quad foohidden@SIZE+1
+.globl _start
+_start:
+  // R_X86_64_SIZE32:
+  movl foo@SIZE-1,%eax
+  movl foo@SIZE,%eax
+  movl foo@SIZE+1,%eax
+  movl foohidden@SIZE-1,%eax
+  movl foohidden@SIZE,%eax
+  movl foohidden@SIZE+1,%eax
diff --git a/test/ELF/relocation-undefined-weak.s b/test/ELF/relocation-undefined-weak.s
new file mode 100644 (file)
index 0000000..6aa84ec
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -sections %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix DISASM
+// REQUIRES: x86
+
+// Check that undefined weak symbols are treated as having a VA of 0.
+
+.global _start
+_start:
+  movl $1, sym1(%rip)
+
+.weak sym1
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x201000
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+// R_86_64_PC32 = 0 + (-8 - (0x201000 + 2)) = -2101258
+
+// DISASM: movl    $1, -2101258(%rip)
diff --git a/test/ELF/relocation.s b/test/ELF/relocation.s
new file mode 100644 (file)
index 0000000..77c7669
--- /dev/null
@@ -0,0 +1,142 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2
+// RUN: ld.lld %t2 -o %t2.so -shared
+// RUN: ld.lld %t %t2.so -o %t3
+// RUN: llvm-readobj -s  %t3 | FileCheck --check-prefix=SEC %s
+// RUN: llvm-objdump -s -d %t3 | FileCheck %s
+// REQUIRES: x86
+
+// SEC:      Name: .plt
+// SEC-NEXT: Type: SHT_PROGBITS
+// SEC-NEXT: Flags [
+// SEC-NEXT:   SHF_ALLOC
+// SEC-NEXT:   SHF_EXECINSTR
+// SEC-NEXT: ]
+// SEC-NEXT: Address: 0x201030
+// SEC-NEXT: Offset: 0x1030
+// SEC-NEXT: Size: 48
+
+// SEC:        Name: .got.plt
+// SEC-NEXT:   Type: SHT_PROGBITS
+// SEC-NEXT:   Flags [
+// SEC-NEXT:     SHF_ALLOC
+// SEC-NEXT:     SHF_WRITE
+// SEC-NEXT:   ]
+// SEC-NEXT:   Address: 0x202000
+// SEC-NEXT:   Offset: 0x2000
+// SEC-NEXT:   Size: 40
+// SEC-NEXT:   Link: 0
+// SEC-NEXT:   Info: 0
+// SEC-NEXT:   AddressAlignment: 8
+// SEC-NEXT:   EntrySize: 0
+// SEC-NEXT:   }
+
+// SEC:         Name: .got
+// SEC-NEXT:   Type: SHT_PROGBITS
+// SEC-NEXT:   Flags [
+// SEC-NEXT:     SHF_ALLOC
+// SEC-NEXT:     SHF_WRITE
+// SEC-NEXT:   ]
+// SEC-NEXT:   Address: 0x2030F0
+// SEC-NEXT:   Offset:
+// SEC-NEXT:   Size: 8
+// SEC-NEXT:   Link: 0
+// SEC-NEXT:   Info: 0
+// SEC-NEXT:   AddressAlignment: 8
+// SEC-NEXT:   EntrySize: 0
+// SEC-NEXT: }
+
+.section       .text,"ax",@progbits,unique,1
+.global _start
+_start:
+  call lulz
+
+.section       .text,"ax",@progbits,unique,2
+.zero 4
+.global lulz
+lulz:
+  nop
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:   201000:  e8 04 00 00 00   callq 4
+// CHECK-NEXT:   201005:
+
+// CHECK:      lulz:
+// CHECK-NEXT:   201009:  90  nop
+
+
+.section       .text2,"ax",@progbits
+.global R_X86_64_32
+R_X86_64_32:
+  movl $R_X86_64_32, %edx
+
+// FIXME: this would be far more self evident if llvm-objdump printed
+// constants in hex.
+// CHECK: Disassembly of section .text2:
+// CHECK-NEXT: R_X86_64_32:
+// CHECK-NEXT:  20100a: {{.*}} movl $2101258, %edx
+
+.section .R_X86_64_32S,"ax",@progbits
+.global R_X86_64_32S
+R_X86_64_32S:
+  movq lulz - 0x100000, %rdx
+
+// CHECK: Disassembly of section .R_X86_64_32S:
+// CHECK-NEXT: R_X86_64_32S:
+// CHECK-NEXT:  {{.*}}: {{.*}} movq 1052681, %rdx
+
+.section .R_X86_64_PC32,"ax",@progbits
+.global R_X86_64_PC32
+R_X86_64_PC32:
+ call bar
+ movl $bar, %eax
+//16 is a size of PLT[0]
+// 0x201030 + 16 - (0x201017 + 5) = 20
+// CHECK:      Disassembly of section .R_X86_64_PC32:
+// CHECK-NEXT: R_X86_64_PC32:
+// CHECK-NEXT:  201017:   {{.*}}  callq  36
+// CHECK-NEXT:  20101c:   {{.*}}  movl $2101312, %eax
+
+.section .R_X86_64_32S_2,"ax",@progbits
+.global R_X86_64_32S_2
+R_X86_64_32S_2:
+  mov bar2, %eax
+// plt is  at 0x201030. The second plt entry is at 0x201050 == 69712
+// CHECK:      Disassembly of section .R_X86_64_32S_2:
+// CHECK-NEXT: R_X86_64_32S_2:
+// CHECK-NEXT: 201021: {{.*}}  movl    2101328, %eax
+
+.section .R_X86_64_64,"a",@progbits
+.global R_X86_64_64
+R_X86_64_64:
+ .quad R_X86_64_64
+
+// CHECK:      Contents of section .R_X86_64_64:
+// CHECK-NEXT:   2001c8 c8012000 00000000
+
+.section .R_X86_64_GOTPCREL,"a",@progbits
+.global R_X86_64_GOTPCREL
+R_X86_64_GOTPCREL:
+ .long zed@gotpcrel
+
+// 0x2020F8 - 0x2001D8 = 7952
+// 7952 = 0x101f0000 in little endian
+// CHECK:      Contents of section .R_X86_64_GOTPCREL
+// CHECK-NEXT:   2001d0 202f0000
+
+.section .R_X86_64_GOT32,"a",@progbits
+.global R_X86_64_GOT32
+R_X86_64_GOT32:
+        .long zed@got
+
+// CHECK: Contents of section .R_X86_64_GOT32:
+// CHECK-NEXT: f8ffffff
+
+
+// CHECK: Contents of section .R_X86_64_GOT64:
+// CHECK-NEXT: f8ffffff ffffffff
+.section .R_X86_64_GOT64,"a",@progbits
+.global R_X86_64_GOT64
+R_X86_64_GOT64:
+        .quad zed@got
diff --git a/test/ELF/relro-omagic.s b/test/ELF/relro-omagic.s
new file mode 100644 (file)
index 0000000..6e9d59a
--- /dev/null
@@ -0,0 +1,34 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so -soname relro-omagic.s.tmp2.so
+# RUN: ld.lld -N %t.o %t2.so -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck --check-prefix=NORELRO %s
+# RUN: llvm-readobj --program-headers %t | FileCheck --check-prefix=NOPHDRS %s
+
+# NORELRO:      Sections:
+# NORELRO-NEXT: Idx Name          Size      Address          Type
+# NORELRO-NEXT:   0               00000000 0000000000000000
+# NORELRO-NEXT:   1 .dynsym       00000048 0000000000200120
+# NORELRO-NEXT:   2 .hash         00000020 0000000000200168
+# NORELRO-NEXT:   3 .dynstr       00000021 0000000000200188
+# NORELRO-NEXT:   4 .rela.dyn     00000018 00000000002001b0
+# NORELRO-NEXT:   5 .rela.plt     00000018 00000000002001c8
+# NORELRO-NEXT:   6 .text         0000000a 00000000002001e0 TEXT DATA
+# NORELRO-NEXT:   7 .plt          00000020 00000000002001f0 TEXT DATA
+# NORELRO-NEXT:   8 .data         00000008 0000000000200210 DATA
+# NORELRO-NEXT:   9 .foo          00000004 0000000000200218 DATA
+# NORELRO-NEXT:  10 .dynamic      000000f0 0000000000200220
+# NORELRO-NEXT:  11 .got          00000008 0000000000200310 DATA
+# NORELRO-NEXT:  12 .got.plt      00000020 0000000000200318 DATA
+
+# NOPHDRS:     ProgramHeaders [
+# NOPHDRS-NOT: PT_GNU_RELRO
+
+.long bar
+jmp *bar2@GOTPCREL(%rip)
+
+.section .data,"aw"
+.quad 0
+
+.section .foo,"aw"
+.zero 4
diff --git a/test/ELF/relro-tls.s b/test/ELF/relro-tls.s
new file mode 100644 (file)
index 0000000..0ee5b6d
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -program-headers %tout | FileCheck %s
+
+// CHECK:      Type: PT_GNU_RELRO
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: VirtualAddress:
+// CHECK-NEXT: PhysicalAddress:
+// CHECK-NEXT: FileSize: 4
+// CHECK-NEXT: MemSize: 4
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   PF_R
+// CHECK-NEXT: ]
+// CHECK-NEXT: Alignment: 1
+
+.global _start
+_start:
+
+.global d
+.section .foo,"awT",@progbits
+d:
+.long 2
diff --git a/test/ELF/relro.s b/test/ELF/relro.s
new file mode 100644 (file)
index 0000000..b21e514
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -z now -z relro -o %t
+// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=FULLRELRO %s
+// RUN: ld.lld %t.o %t2.so -z relro -o %t
+// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=PARTRELRO %s
+// RUN: ld.lld %t.o %t2.so -z norelro -o %t
+// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=NORELRO %s
+// REQUIRES: x86
+
+// CHECK:      Program Headers:
+// CHECK-NEXT: Type
+// CHECK-NEXT: PHDR
+// CHECK-NEXT: LOAD
+// CHECK-NEXT: LOAD
+// CHECK-NEXT: LOAD
+// CHECK-NEXT: DYNAMIC
+// CHECK-NEXT: GNU_RELRO
+// CHECK: Section to Segment mapping:
+
+// FULLRELRO:  05     .openbsd.randomdata .dynamic .got .got.plt {{$}}
+// PARTRELRO:  05     .openbsd.randomdata .dynamic .got {{$}}
+
+
+// NORELRO-NOT: GNU_RELRO
+
+.global _start
+_start:
+  .long bar
+  jmp *bar2@GOTPCREL(%rip)
+
+.section .data,"aw"
+.quad 0
+
+.zero 4
+.section .foo,"aw"
+.section .bss,"",@nobits
+
+.section .openbsd.randomdata, "aw"
+.quad 0
diff --git a/test/ELF/reproduce-backslash.s b/test/ELF/reproduce-backslash.s
new file mode 100644 (file)
index 0000000..53feb5f
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86, shell
+
+# Test that we don't erroneously replace \ with / on UNIX, as it's
+# legal for a filename to contain backslashes.
+# RUN: llvm-mc %s -o foo\\.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: ld.lld foo\\.o --reproduce repro.tar
+# RUN: tar tf repro.tar | FileCheck %s
+
+# CHECK: repro/{{.*}}/foo\\.o
diff --git a/test/ELF/reproduce-error.s b/test/ELF/reproduce-error.s
new file mode 100644 (file)
index 0000000..e2de8a4
--- /dev/null
@@ -0,0 +1,14 @@
+# Extracting the tar archive can get over the path limit on windows.
+# REQUIRES: shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir
+# RUN: cd %t.dir
+
+# RUN: not ld.lld --reproduce repro.tar abc -o t 2>&1 | FileCheck %s
+# CHECK: cannot open abc: {{N|n}}o such file or directory
+
+# RUN: tar xf repro.tar
+# RUN: FileCheck --check-prefix=RSP %s < repro/response.txt
+# RSP: abc
+# RSP: -o t
diff --git a/test/ELF/reproduce-linkerscript.s b/test/ELF/reproduce-linkerscript.s
new file mode 100644 (file)
index 0000000..2b00815
--- /dev/null
@@ -0,0 +1,20 @@
+# REQUIRES: x86, shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build/foo.o
+# RUN: echo "INPUT(\"%t.dir/build/foo.o\")" > %t.dir/build/foo.script
+# RUN: echo "INCLUDE \"%t.dir/build/bar.script\"" >> %t.dir/build/foo.script
+# RUN: echo "/* empty */" > %t.dir/build/bar.script
+# RUN: cd %t.dir
+# RUN: ld.lld build/foo.script -o bar --reproduce repro.tar
+# RUN: tar xf repro.tar
+# RUN: diff build/foo.script repro/%:t.dir/build/foo.script
+# RUN: diff build/bar.script repro/%:t.dir/build/bar.script
+# RUN: diff build/foo.o repro/%:t.dir/build/foo.o
+
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/reproduce-thin-archive.s b/test/ELF/reproduce-thin-archive.s
new file mode 100644 (file)
index 0000000..2de88d7
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86, shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.dir/foo.o
+# RUN: cd %t.dir
+# RUN: llvm-ar --format=gnu rcT foo.a foo.o
+# RUN: ld.lld -m elf_x86_64 foo.a -o bar --reproduce repro.tar
+# RUN: tar xf repro.tar
+# RUN: diff foo.a repro/%:t.dir/foo.a
+# RUN: diff foo.o repro/%:t.dir/foo.o
+
+.globl _start
+_start:
+  nop
diff --git a/test/ELF/reproduce-windows.s b/test/ELF/reproduce-windows.s
new file mode 100644 (file)
index 0000000..6dd1fe2
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+
+# Test that a repro archive always uses / instead of \.
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build
+# RUN: llvm-mc %s -o %t.dir/build/foo.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: cd %t.dir
+# RUN: ld.lld build/foo.o --reproduce repro.tar
+# RUN: tar tf repro.tar | FileCheck %s
+
+# CHECK: repro/response.txt
+# CHECK: repro/{{.*}}/build/foo.o
diff --git a/test/ELF/reproduce-windows2.s b/test/ELF/reproduce-windows2.s
new file mode 100644 (file)
index 0000000..38e0024
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: system-windows, x86
+
+# Test that a response.txt file always uses / instead of \.
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build
+# RUN: llvm-mc %s -o %t.dir/build/foo.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: cd %t.dir
+# RUN: ld.lld build/foo.o --reproduce repro.tar
+# RUN: tar -O -x -f repro.tar repro/response.txt | FileCheck %s
+# CHECK: {{.*}}/build/foo.o
diff --git a/test/ELF/reproduce.s b/test/ELF/reproduce.s
new file mode 100644 (file)
index 0000000..0a93be0
--- /dev/null
@@ -0,0 +1,75 @@
+# REQUIRES: x86
+
+# Extracting the tar archive can get over the path limit on windows.
+# REQUIRES: shell
+
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir/build1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build1/foo.o
+# RUN: cd %t.dir
+# RUN: ld.lld --hash-style=gnu build1/foo.o -o bar -shared --as-needed --reproduce repro.tar
+# RUN: tar xf repro.tar
+# RUN: diff build1/foo.o repro/%:t.dir/build1/foo.o
+
+# RUN: FileCheck %s --check-prefix=RSP < repro/response.txt
+# RSP: {{^}}--hash-style gnu{{$}}
+# RSP-NOT: repro{{[/\\]}}
+# RSP-NEXT: {{[/\\]}}foo.o
+# RSP-NEXT: -o bar
+# RSP-NEXT: -shared
+# RSP-NEXT: --as-needed
+
+# RUN: FileCheck %s --check-prefix=VERSION < repro/version.txt
+# VERSION: LLD
+
+# RUN: mkdir -p %t.dir/build2/a/b/c
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.dir/build2/foo.o
+# RUN: cd %t.dir/build2/a/b/c
+# RUN: env LLD_REPRODUCE=repro.tar ld.lld ./../../../foo.o -o bar -shared --as-needed
+# RUN: tar xf repro.tar
+# RUN: diff %t.dir/build2/foo.o repro/%:t.dir/build2/foo.o
+
+# RUN: echo "{ local: *; };" >  ver
+# RUN: echo "{};" > dyn
+# RUN: echo > file
+# RUN: echo > file2
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o 'foo bar'
+# RUN: ld.lld --reproduce repro2.tar 'foo bar' -L"foo bar" -Lfile -Tfile2 \
+# RUN:   --dynamic-list dyn -rpath file --script=file --version-script ver \
+# RUN:   --dynamic-linker "some unusual/path" -soname 'foo bar' -soname='foo bar'
+# RUN: tar xf repro2.tar
+# RUN: FileCheck %s --check-prefix=RSP2 < repro2/response.txt
+# RSP2:      "{{.*}}foo bar"
+# RSP2-NEXT: -L "{{.*}}foo bar"
+# RSP2-NEXT: -L {{.+}}file
+# RSP2-NEXT: --script {{.+}}file2
+# RSP2-NEXT: --dynamic-list {{.+}}dyn
+# RSP2-NEXT: -rpath {{.+}}file
+# RSP2-NEXT: --script {{.+}}file
+# RSP2-NEXT: --version-script [[PATH:.*]]ver
+# RSP2-NEXT: --dynamic-linker "some unusual/path"
+# RSP2-NEXT: -soname="foo bar"
+# RSP2-NEXT: -soname="foo bar"
+
+# RUN: tar tf repro2.tar | FileCheck %s
+# CHECK:      repro2/response.txt
+# CHECK-NEXT: repro2/version.txt
+# CHECK-NEXT: repro2/{{.*}}/dyn
+# CHECK-NEXT: repro2/{{.*}}/ver
+# CHECK-NEXT: repro2/{{.*}}/foo bar
+# CHECK-NEXT: repro2/{{.*}}/file2
+# CHECK-NEXT: repro2/{{.*}}/file
+
+## Check that directory path is stripped from -o <file-path>
+# RUN: mkdir -p %t.dir/build3/a/b/c
+# RUN: cd %t.dir
+# RUN: ld.lld build1/foo.o -o build3/a/b/c/bar -shared --as-needed --reproduce=repro3.tar
+# RUN: tar xf repro3.tar
+# RUN: FileCheck %s --check-prefix=RSP3 < repro3/response.txt
+# RSP3: -o bar
+
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/resolution-end.s b/test/ELF/resolution-end.s
new file mode 100644 (file)
index 0000000..aa1c999
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-end.s -o %t2.o
+# RUN: ld.lld -shared -o %t2.so %t2.o
+# RUN: ld.lld %t1.o %t2.so -o %t
+# RUN: llvm-readobj -t -s -section-data  %t | FileCheck %s
+# REQUIRES: x86
+
+# Test that we resolve _end to the this executable.
+
+# CHECK:      Name: .text
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT:   SHF_ALLOC
+# CHECK-NEXT:   SHF_EXECINSTR
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT:   0000: 80202000 00000000 80202000 00000000
+# CHECK-NEXT: )
+
+# CHECK:      Symbol {
+# CHECK:        Name: _end
+# CHECK-NEXT:   Value: 0x202080
+
+# CHECK:      Symbol {
+# CHECK:        Name: end
+# CHECK-NEXT:   Value: 0x202080
+
+.global _start
+_start:
+.quad _end
+.quad end
diff --git a/test/ELF/resolution-shared.s b/test/ELF/resolution-shared.s
new file mode 100644 (file)
index 0000000..e1eac07
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-shared.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t3 -shared
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+// REQUIRES: x86
+
+        .weak foo
+foo:
+
+// CHECK:      Symbol {
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Binding: Weak
diff --git a/test/ELF/resolution.s b/test/ELF/resolution.s
new file mode 100644 (file)
index 0000000..4a42d94
--- /dev/null
@@ -0,0 +1,430 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2
+// RUN: ld.lld -discard-all %t %t2 -o %t3
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+// REQUIRES: x86
+
+// This is an exhaustive test for checking which symbol is kept when two
+// have the same name. Each symbol has a different size which is used
+// to see which one was chosen.
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 63
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 30
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 55
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 22
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 27
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonStrong_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 26
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 61
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 28
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 53
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 20
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 25
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: CommonWeak_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 24
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 10
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 9
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 2
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 6
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularStrong_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 5
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 40
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 7
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 33
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_UndefStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: RegularWeak_with_UndefWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 3
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 51
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 50
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 46
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefStrong_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 45
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_CommonStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 49
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_CommonWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 48
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_RegularStrong
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 44
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_RegularWeak
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 43
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: UndefWeak_with_UndefWeak
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:  Symbol {
+// CHECK-NEXT:    Name: _start
+// CHECK-NEXT:    Value: 0x201000
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global (0x1)
+// CHECK-NEXT:    Type: None (0x0)
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .text (0x1)
+// CHECK-NEXT:  }
+// CHECK-NEXT: ]
+
+.globl _start
+_start:
+        nop
+
+local:
+
+.weak RegularWeak_with_RegularWeak
+.size RegularWeak_with_RegularWeak, 0
+RegularWeak_with_RegularWeak:
+
+.weak RegularWeak_with_RegularStrong
+.size RegularWeak_with_RegularStrong, 1
+RegularWeak_with_RegularStrong:
+
+.global RegularStrong_with_RegularWeak
+.size RegularStrong_with_RegularWeak, 2
+RegularStrong_with_RegularWeak:
+
+.weak RegularWeak_with_UndefWeak
+.size RegularWeak_with_UndefWeak, 3
+RegularWeak_with_UndefWeak:
+
+.weak RegularWeak_with_UndefStrong
+.size RegularWeak_with_UndefStrong, 4
+RegularWeak_with_UndefStrong:
+
+.global RegularStrong_with_UndefWeak
+.size RegularStrong_with_UndefWeak, 5
+RegularStrong_with_UndefWeak:
+
+.global RegularStrong_with_UndefStrong
+.size RegularStrong_with_UndefStrong, 6
+RegularStrong_with_UndefStrong:
+
+.weak RegularWeak_with_CommonWeak
+.size RegularWeak_with_CommonWeak, 7
+RegularWeak_with_CommonWeak:
+
+.weak RegularWeak_with_CommonStrong
+.size RegularWeak_with_CommonStrong, 8
+RegularWeak_with_CommonStrong:
+
+.global RegularStrong_with_CommonWeak
+.size RegularStrong_with_CommonWeak, 9
+RegularStrong_with_CommonWeak:
+
+.global RegularStrong_with_CommonStrong
+.size RegularStrong_with_CommonStrong, 10
+RegularStrong_with_CommonStrong:
+
+.weak UndefWeak_with_RegularWeak
+.size UndefWeak_with_RegularWeak, 11
+.quad UndefWeak_with_RegularWeak
+
+.weak UndefWeak_with_RegularStrong
+.size UndefWeak_with_RegularStrong, 12
+.quad UndefWeak_with_RegularStrong
+
+.size UndefStrong_with_RegularWeak, 13
+.quad UndefStrong_with_RegularWeak
+
+.size UndefStrong_with_RegularStrong, 14
+.quad UndefStrong_with_RegularStrong
+
+.weak UndefWeak_with_UndefWeak
+.size UndefWeak_with_UndefWeak, 15
+.quad UndefWeak_with_UndefWeak
+
+.weak UndefWeak_with_CommonWeak
+.size UndefWeak_with_CommonWeak, 16
+.quad UndefWeak_with_CommonWeak
+
+.weak UndefWeak_with_CommonStrong
+.size UndefWeak_with_CommonStrong, 17
+.quad UndefWeak_with_CommonStrong
+
+.size UndefStrong_with_CommonWeak, 18
+.quad UndefStrong_with_CommonWeak
+
+.size UndefStrong_with_CommonStrong, 19
+.quad UndefStrong_with_CommonStrong
+
+.weak CommonWeak_with_RegularWeak
+.comm CommonWeak_with_RegularWeak,20,4
+
+.weak CommonWeak_with_RegularStrong
+.comm CommonWeak_with_RegularStrong,21,4
+
+.comm CommonStrong_with_RegularWeak,22,4
+
+.comm CommonStrong_with_RegularStrong,23,4
+
+.weak CommonWeak_with_UndefWeak
+.comm CommonWeak_with_UndefWeak,24,4
+
+.weak CommonWeak_with_UndefStrong
+.comm CommonWeak_with_UndefStrong,25,4
+
+.comm CommonStrong_with_UndefWeak,26,4
+
+.comm CommonStrong_with_UndefStrong,27,4
+
+.weak CommonWeak_with_CommonWeak
+.comm CommonWeak_with_CommonWeak,28,4
+
+.weak CommonWeak_with_CommonStrong
+.comm CommonWeak_with_CommonStrong,29,4
+
+.comm CommonStrong_with_CommonWeak,30,4
+
+.comm CommonStrong_with_CommonStrong,31,4
diff --git a/test/ELF/retain-symbols-file.s b/test/ELF/retain-symbols-file.s
new file mode 100644 (file)
index 0000000..aa7d35d
--- /dev/null
@@ -0,0 +1,74 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: echo "bar" > %t_retain.txt
+# RUN: echo "foo" >> %t_retain.txt
+# RUN: ld.lld -shared --retain-symbols-file=%t_retain.txt %t -o %t2
+# RUN: llvm-readobj --dyn-symbols %t2 | FileCheck %s
+
+## Check separate form.
+# RUN: ld.lld -shared --retain-symbols-file %t_retain.txt %t -o %t2
+# RUN: llvm-readobj --dyn-symbols %t2 | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: bar
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: und
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.text
+.globl _start
+_start:
+call zed@PLT
+call und@PLT
+
+.globl foo
+.type foo,@function
+foo:
+retq
+
+.globl bar
+.type bar,@function
+bar:
+retq
+
+.globl zed
+.type zed,@function
+zed:
+retq
+
+.type loc,@function
+loc:
+retq
diff --git a/test/ELF/retain-und.s b/test/ELF/retain-und.s
new file mode 100644 (file)
index 0000000..2f34675
--- /dev/null
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo  > %t.retain
+# RUN: echo "{ local: *; }; " > %t.script
+# RUN: ld.lld -shared --version-script %t.script %t.o -o %t1.so
+# RUN: ld.lld -shared --retain-symbols-file %t.retain %t.o -o %t2.so
+# RUN: llvm-readobj -r %t1.so | FileCheck %s
+# RUN: llvm-readobj -r %t2.so | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x{{.*}} R_X86_64_64 foo 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.data
+.quad foo
+.weak foo
diff --git a/test/ELF/rodynamic.s b/test/ELF/rodynamic.s
new file mode 100644 (file)
index 0000000..441e5c3
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+# RUN: llvm-mc %p/Inputs/rodynamic.s -o %t.so.o -filetype=obj -triple=x86_64-pc-linux
+
+# RUN: ld.lld -shared %t.so.o -o %t.so
+# RUN: ld.lld %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DEFDEBUG %s
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=DEFSEC %s
+
+# RUN: ld.lld -shared -z rodynamic %t.so.o -o %t.so
+# RUN: ld.lld -z rodynamic %t.o %t.so -o %t.exe
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=RODEBUG %s
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=ROSEC %s
+
+.globl _start
+_start:
+  call foo
+
+# DEFDEBUG: DEBUG
+
+# DEFSEC:      Section {
+# DEFSEC:        Name: .dynamic
+# DEFSEC-NEXT:   Type: SHT_DYNAMIC
+# DEFSEC-NEXT:   Flags [
+# DEFSEC-NEXT:     SHF_ALLOC
+# DEFSEC-NEXT:     SHF_WRITE
+# DEFSEC-NEXT:   ]
+
+# RODEBUG-NOT: DEBUG
+
+# ROSEC:      Section {
+# ROSEC:        Name: .dynamic
+# ROSEC-NEXT:   Type: SHT_DYNAMIC
+# ROSEC-NEXT:   Flags [
+# ROSEC-NEXT:     SHF_ALLOC
+# ROSEC-NEXT:   ]
diff --git a/test/ELF/section-align-0.test b/test/ELF/section-align-0.test
new file mode 100644 (file)
index 0000000..35783f5
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: yaml2obj %s -o %t
+# RUN: ld.lld %t -o %tout
+
+# Verify that lld can handle sections with an alignment of zero.
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    AddressAlign:    0
+
+Symbols:
+  Global:
+    - Name:            _start
+      Section:         .text
diff --git a/test/ELF/section-layout.s b/test/ELF/section-layout.s
new file mode 100644 (file)
index 0000000..7febec8
--- /dev/null
@@ -0,0 +1,59 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %tout
+# RUN: llvm-readobj -sections %tout | FileCheck %s
+# REQUIRES: x86
+
+# Check that sections are laid out in the correct order.
+
+.global _start
+.text
+_start:
+
+.section t,"x",@nobits
+.section s,"x"
+.section r,"w",@nobits
+.section q,"w"
+.section p,"wx",@nobits
+.section o,"wx"
+.section n,"",@nobits
+.section m,""
+
+.section l,"awx",@nobits
+.section k,"awx"
+.section j,"aw",@nobits
+.section i,"aw"
+.section g,"awT",@nobits
+.section e,"awT"
+.section d,"ax",@nobits
+.section c,"ax"
+.section b,"a",@nobits
+.section a,"a"
+
+// CHECK: Name: a
+// CHECK: Name: b
+// CHECK: Name: c
+// CHECK: Name: d
+
+// Sections that are both writable and executable appear before
+// sections that are only writable.
+// CHECK: Name: k
+// CHECK: Name: l
+
+// Writable sections appear before TLS and other relro sections.
+// CHECK: Name: i
+
+// TLS sections are only sorted on NOBITS.
+// CHECK: Name: e
+// CHECK: Name: g
+
+// CHECK: Name: j
+
+// Non allocated sections are in input order.
+// CHECK: Name: t
+// CHECK: Name: s
+// CHECK: Name: r
+// CHECK: Name: q
+// CHECK: Name: p
+// CHECK: Name: o
+// CHECK: Name: n
+// CHECK: Name: m
diff --git a/test/ELF/section-metadata-err.s b/test/ELF/section-metadata-err.s
new file mode 100644 (file)
index 0000000..f3b5842
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: error: Merge and .eh_frame sections are not supported with SHF_LINK_ORDER {{.*}}section-metadata-err.s.tmp.o:(.foo)
+
+.global _start
+_start:
+.quad .foo
+
+.section .foo,"aM",@progbits,8
+.quad 0
+
+.section bar,"ao",@progbits,.foo
diff --git a/test/ELF/section-name.s b/test/ELF/section-name.s
new file mode 100644 (file)
index 0000000..caf574f
--- /dev/null
@@ -0,0 +1,58 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %tout
+# RUN: llvm-objdump --section-headers  %tout | FileCheck %s
+# REQUIRES: x86
+
+.global _start
+.text
+_start:
+
+.section .text.a,"ax"
+.byte 0
+.section .text.,"ax"
+.byte 0
+.section .rodata.a,"a"
+.byte 0
+.section .rodata,"a"
+.byte 0
+.section .data.a,"aw"
+.byte 0
+.section .data,"aw"
+.byte 0
+.section .bss.a,"aw",@nobits
+.byte 0
+.section .bss,"aw",@nobits
+.byte 0
+.section .foo.a,"aw"
+.byte 0
+.section .foo,"aw"
+.byte 0
+.section .data.rel.ro,"aw",%progbits
+.byte 0
+.section .data.rel.ro.a,"aw",%progbits
+.byte 0
+.section .data.rel.ro.local,"aw",%progbits
+.byte 0
+.section .data.rel.ro.local.a,"aw",%progbits
+.byte 0
+.section .tbss.foo,"aGwT",@nobits,foo,comdat
+.byte 0
+.section .gcc_except_table.foo,"aG",@progbits,foo,comdat
+.byte 0
+.section .tdata.foo,"aGwT",@progbits,foo,comdat
+.byte 0
+
+// CHECK:  1 .rodata  00000002
+// CHECK:  2 .gcc_except_table 00000001
+// CHECK:  3 .text         00000002
+// CHECK:  4 .data         00000002
+// CHECK:  5 .foo.a        00000001
+// CHECK:  6 .foo          00000001
+// CHECK:  7 .tdata        00000001
+// CHECK:  8 .tbss         00000001
+// CHECK:  9 .data.rel.ro  00000004
+// CHECK: 10 .bss          00000002
+// CHECK: 11 .comment      00000008
+// CHECK: 12 .symtab       00000030
+// CHECK: 13 .shstrtab     00000075
+// CHECK: 14 .strtab       00000008
diff --git a/test/ELF/section-symbol.s b/test/ELF/section-symbol.s
new file mode 100644 (file)
index 0000000..5cf71ac
--- /dev/null
@@ -0,0 +1,40 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld %t -o %t.so -shared -discard-none
+// RUN: llvm-readobj -t %t.so | FileCheck %s
+
+// Test that we don't include the section symbols from the .o in the .so
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+foo:
+        .quad foo - .
diff --git a/test/ELF/section-symbols.test b/test/ELF/section-symbols.test
new file mode 100644 (file)
index 0000000..2ef77a8
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: yaml2obj %s -o %t
+# RUN: ld.lld -shared %t -o %tout
+
+# Verify that lld can handle STT_SECTION symbols associated
+# with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections.
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_FREEBSD
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         "00000000"
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:
+Symbols:
+  Local:
+    - Type:            STT_SECTION
+      Section:         .rela.text
+    - Type:            STT_SECTION
+      Section:         .shstrtab
+    - Type:            STT_SECTION
+      Section:         .symtab
+    - Type:            STT_SECTION
+      Section:         .strtab
diff --git a/test/ELF/sectionstart-noallochdr.s b/test/ELF/sectionstart-noallochdr.s
new file mode 100644 (file)
index 0000000..e9267a5
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o --section-start .data=0x20 \
+# RUN: --section-start .bss=0x30 --section-start .text=0x10 -o %t1
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT:  Idx Name          Size      Address          Type
+# CHECK-NEXT:    0               00000000 0000000000000000
+# CHECK-NEXT:    1 .text         00000001 0000000000000010 TEXT DATA
+# CHECK-NEXT:    2 .data         00000004 0000000000000020 DATA
+# CHECK-NEXT:    3 .bss          00000004 0000000000000030 BSS
+
+.text
+.globl _start
+_start:
+ nop
+
+.data
+.long 0
+
+.bss
+.zero 4
diff --git a/test/ELF/sectionstart.s b/test/ELF/sectionstart.s
new file mode 100644 (file)
index 0000000..23574c1
--- /dev/null
@@ -0,0 +1,67 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o --section-start .text=0x100000 \
+# RUN:   --section-start .data=0x110000 --section-start .bss=0x200000 -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT:  Idx Name          Size      Address          Type
+# CHECK-NEXT:    0               00000000 0000000000000000
+# CHECK-NEXT:    1 .text         00000001 0000000000100000 TEXT DATA
+# CHECK-NEXT:    2 .data         00000004 0000000000110000 DATA
+# CHECK-NEXT:    3 .bss          00000004 0000000000200000 BSS
+
+## The same, but dropped "0x" prefix.
+# RUN: ld.lld %t.o --section-start .text=100000 \
+# RUN:   --section-start .data=110000 --section-start .bss=0x200000 -o %t1
+# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
+
+## Use -Ttext, -Tdata, -Tbss as replacement for --section-start:
+# RUN: ld.lld %t.o -Ttext=0x100000 -Tdata=0x110000 -Tbss=0x200000 -o %t4
+# RUN: llvm-objdump -section-headers %t4 | FileCheck %s
+
+## Check Ttext-segment X and Ttext-segment=X forms.
+# RUN: ld.lld %t.o -Ttext-segment=0x100000 -Tdata=0x110000 -Tbss=0x200000 -o %t4
+# RUN: llvm-objdump -section-headers %t4 | FileCheck %s
+# RUN: ld.lld %t.o -Ttext-segment 0x100000 -Tdata=0x110000 -Tbss=0x200000 -o %t4
+# RUN: llvm-objdump -section-headers %t4 | FileCheck %s
+
+## The same, but dropped "0x" prefix.
+# RUN: ld.lld %t.o -Ttext=100000 -Tdata=110000 -Tbss=200000 -o %t5
+# RUN: llvm-objdump -section-headers %t5 | FileCheck %s
+
+## Check form without assignment:
+# RUN: ld.lld %t.o -Ttext 0x100000 -Tdata 0x110000 -Tbss 0x200000 -o %t4
+# RUN: llvm-objdump -section-headers %t4 | FileCheck %s
+
+## Errors:
+# RUN: not ld.lld %t.o --section-start .text100000 -o %t2 2>&1 \
+# RUN:    | FileCheck -check-prefix=ERR1 %s
+# ERR1: invalid argument: --section-start .text100000
+
+# RUN: not ld.lld %t.o --section-start .text=1Q0000 -o %t3 2>&1 \
+# RUN:    | FileCheck -check-prefix=ERR2 %s
+# ERR2: invalid argument: --section-start .text=1Q0000
+
+# RUN: not ld.lld %t.o -Ttext=1w0000 -o %t6 2>&1 \
+# RUN:    | FileCheck -check-prefix=ERR3 %s
+# ERR3: invalid argument: --Ttext 1w0000
+
+# RUN: not ld.lld %t.o -Tbss=1w0000 -o %t6 2>&1 \
+# RUN:    | FileCheck -check-prefix=ERR4 %s
+# ERR4: invalid argument: --Tbss 1w0000
+
+# RUN: not ld.lld %t.o -Tdata=1w0000 -o %t6 2>&1 \
+# RUN:    | FileCheck -check-prefix=ERR5 %s
+# ERR5: invalid argument: --Tdata 1w0000
+
+.text
+.globl _start
+_start:
+ nop
+
+.data
+.long 0
+
+.bss
+.zero 4
diff --git a/test/ELF/segments.s b/test/ELF/segments.s
new file mode 100644 (file)
index 0000000..9307ba3
--- /dev/null
@@ -0,0 +1,108 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t1
+# RUN: llvm-readobj --program-headers %t1 | FileCheck --check-prefix=ROSEGMENT %s
+
+# ROSEGMENT:      ProgramHeader {
+# ROSEGMENT:        Type: PT_LOAD
+# ROSEGMENT-NEXT:    Offset: 0x0
+# ROSEGMENT-NEXT:    VirtualAddress:
+# ROSEGMENT-NEXT:    PhysicalAddress:
+# ROSEGMENT-NEXT:    FileSize:
+# ROSEGMENT-NEXT:    MemSize:
+# ROSEGMENT-NEXT:    Flags [
+# ROSEGMENT-NEXT:      PF_R
+# ROSEGMENT-NEXT:    ]
+# ROSEGMENT-NEXT:    Alignment: 4096
+# ROSEGMENT-NEXT:  }
+# ROSEGMENT-NEXT:  ProgramHeader {
+# ROSEGMENT-NEXT:    Type: PT_LOAD
+# ROSEGMENT-NEXT:    Offset: 0x1000
+# ROSEGMENT-NEXT:    VirtualAddress:
+# ROSEGMENT-NEXT:    PhysicalAddress:
+# ROSEGMENT-NEXT:    FileSize:
+# ROSEGMENT-NEXT:    MemSize:
+# ROSEGMENT-NEXT:    Flags [
+# ROSEGMENT-NEXT:      PF_R
+# ROSEGMENT-NEXT:      PF_X
+# ROSEGMENT-NEXT:    ]
+# ROSEGMENT-NEXT:    Alignment: 4096
+# ROSEGMENT-NEXT:  }
+# ROSEGMENT-NEXT:  ProgramHeader {
+# ROSEGMENT-NEXT:    Type: PT_LOAD
+# ROSEGMENT-NEXT:    Offset: 0x2000
+# ROSEGMENT-NEXT:    VirtualAddress:
+# ROSEGMENT-NEXT:    PhysicalAddress:
+# ROSEGMENT-NEXT:    FileSize: 1
+# ROSEGMENT-NEXT:    MemSize: 1
+# ROSEGMENT-NEXT:    Flags [
+# ROSEGMENT-NEXT:      PF_R
+# ROSEGMENT-NEXT:      PF_W
+# ROSEGMENT-NEXT:    ]
+# ROSEGMENT-NEXT:    Alignment: 4096
+# ROSEGMENT-NEXT:  }
+
+# RUN: ld.lld -no-rosegment %t -o %t2
+# RUN: llvm-readobj --program-headers %t2 | FileCheck --check-prefix=NOROSEGMENT %s
+
+# NOROSEGMENT:     ProgramHeader {
+# NOROSEGMENT:       Type: PT_LOAD
+# NOROSEGMENT-NEXT:   Offset: 0x0
+# NOROSEGMENT-NEXT:   VirtualAddress:
+# NOROSEGMENT-NEXT:   PhysicalAddress:
+# NOROSEGMENT-NEXT:   FileSize:
+# NOROSEGMENT-NEXT:   MemSize:
+# NOROSEGMENT-NEXT:   Flags [
+# NOROSEGMENT-NEXT:     PF_R
+# NOROSEGMENT-NEXT:     PF_X
+# NOROSEGMENT-NEXT:   ]
+# NOROSEGMENT-NEXT:   Alignment: 4096
+# NOROSEGMENT-NEXT: }
+# NOROSEGMENT-NEXT: ProgramHeader {
+# NOROSEGMENT-NEXT:   Type: PT_LOAD
+# NOROSEGMENT-NEXT:   Offset: 0x1000
+# NOROSEGMENT-NEXT:   VirtualAddress:
+# NOROSEGMENT-NEXT:   PhysicalAddress:
+# NOROSEGMENT-NEXT:   FileSize:
+# NOROSEGMENT-NEXT:   MemSize:
+# NOROSEGMENT-NEXT:   Flags [
+# NOROSEGMENT-NEXT:     PF_R
+# NOROSEGMENT-NEXT:     PF_W
+# NOROSEGMENT-NEXT:   ]
+# NOROSEGMENT-NEXT:   Alignment: 4096
+# NOROSEGMENT-NEXT: }
+# NOROSEGMENT-NEXT: ProgramHeader {
+# NOROSEGMENT-NEXT:   Type: PT_GNU_STACK
+
+# RUN: ld.lld -N %t -o %t3
+# RUN: llvm-readobj --program-headers %t3 | FileCheck --check-prefix=OMAGIC %s
+
+# OMAGIC:     ProgramHeader {
+# OMAGIC:      Type: PT_LOAD
+# OMAGIC-NEXT:   Offset: 0x0
+# OMAGIC-NEXT:   VirtualAddress:
+# OMAGIC-NEXT:   PhysicalAddress:
+# OMAGIC-NEXT:   FileSize:
+# OMAGIC-NEXT:   MemSize:
+# OMAGIC-NEXT:   Flags [
+# OMAGIC-NEXT:     PF_R
+# OMAGIC-NEXT:     PF_W
+# OMAGIC-NEXT:     PF_X
+# OMAGIC-NEXT:   ]
+# OMAGIC-NEXT:   Alignment: 4096
+# OMAGIC-NEXT: }
+# OMAGIC-NEXT: ProgramHeader {
+# OMAGIC-NEXT:   Type: PT_GNU_STACK
+
+.global _start
+_start:
+ nop
+
+.section .ro,"a"
+nop
+
+.section .rw,"aw"
+nop
+
+.section .rx,"ax"
+nop
diff --git a/test/ELF/shared-be.s b/test/ELF/shared-be.s
new file mode 100644 (file)
index 0000000..0b941d3
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s
+// REQUIRES: ppc
+
+// CHECK:      Name: .rela.dyn
+// CHECK-NEXT: Type: SHT_REL
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[RELADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[RELSIZE:.*]]
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize: [[RELENT:.*]]
+
+// CHECK:      DynamicSection [
+// CHECK-NEXT:   Tag                Type                 Name/Value
+// CHECK-NEXT:   0x000000000000001D RUNPATH              foo:bar
+// CHECK-NEXT:   0x0000000000000001 NEEDED               Shared library: [{{.*}}2.so]
+// CHECK-NEXT:   0x0000000000000015 DEBUG                0x0
+// CHECK-NEXT:   0x0000000000000007 RELA                 [[RELADDR]]
+// CHECK-NEXT:   0x0000000000000008 RELASZ               [[RELSIZE]] (bytes)
+// CHECK-NEXT:   0x0000000000000009 RELAENT              [[RELENT]] (bytes)
+// CHECK:        0x0000000000000000 NULL                 0x0
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+.data
+.long bar
+.long zed
+
diff --git a/test/ELF/shared.s b/test/ELF/shared.s
new file mode 100644 (file)
index 0000000..d4c79d9
--- /dev/null
@@ -0,0 +1,305 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: llvm-readobj -s %t2.so | FileCheck --check-prefix=SO %s
+// RUN: ld.lld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data -hash-table %t | FileCheck %s
+// RUN: ld.lld %t.o %t2.so %t2.so -o %t2
+// RUN: llvm-readobj -dyn-symbols %t2 | FileCheck --check-prefix=DONT_EXPORT %s
+// REQUIRES: x86
+
+// Make sure .symtab is properly aligned.
+// SO:      Name: .symtab
+// SO-NEXT: Type: SHT_SYMTAB
+// SO-NEXT: Flags [
+// SO-NEXT: ]
+// SO-NEXT: Address:
+// SO-NEXT: Offset: 0x1038
+// SO-NEXT: Size:
+// SO-NEXT: Link:
+// SO-NEXT: Info:
+// SO-NEXT: AddressAlignment: 4
+
+// CHECK:        Name: .interp
+// CHECK-NEXT:   Type: SHT_PROGBITS
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[INTERPADDR:.*]]
+// CHECK-NEXT:   Offset: [[INTERPOFFSET:.*]]
+// CHECK-NEXT:   Size: [[INTERPSIZE:.*]]
+// CHECK-NEXT:   Link: 0
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment: 1
+// CHECK-NEXT:   EntrySize: 0
+// CHECK-NEXT:   SectionData (
+// CHECK-NEXT:     0000: 2F6C6962 36342F6C 642D6C69 6E75782D  |/lib64/ld-linux-|
+// CHECK-NEXT:     0010: 7838362D 36342E73 6F2E3200           |x86-64.so.2.|
+// CHECK-NEXT:   )
+// CHECK-NEXT: }
+
+// test that .hash is linked to .dynsym
+// CHECK:        Index: 2
+// CHECK-NEXT:   Name: .dynsym
+// CHECK-NEXT:   Type: SHT_DYNSYM
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[DYNSYMADDR:.*]]
+// CHECK-NEXT:   Offset: 0x150
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Link: [[DYNSTR:.*]]
+// CHECK-NEXT:   Info: 1
+// CHECK-NEXT:   AddressAlignment: 4
+// CHECK-NEXT:   EntrySize: 16
+// CHECK-NEXT:   SectionData (
+// CHECK-NEXT:     0000:
+// CHECK-NEXT:     0010:
+// CHECK-NEXT:     0020:
+// CHECK-NEXT:     0030:
+// CHECK-NEXT:   )
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT:   Index: 3
+// CHECK-NEXT:    Name: .hash
+// CHECK-NEXT:    Type: SHT_HASH
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: [[HASHADDR:.*]]
+// CHECK-NEXT:    Offset:
+// CHECK-NEXT:    Size:
+// CHECK-NEXT:    Link: 2
+// CHECK-NEXT:    Info: 0
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize: 4
+
+// CHECK:        Index: [[DYNSTR]]
+// CHECK-NEXT:   Name: .dynstr
+// CHECK-NEXT:   Type: SHT_STRTAB
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[DYNSTRADDR:.*]]
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   Size:
+// CHECK-NEXT:   Link: 0
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment: 1
+// CHECK-NEXT:   EntrySize: 0
+// CHECK-NEXT:   SectionData (
+// CHECK:        )
+// CHECK-NEXT: }
+
+// CHECK:      Name: .rel.dyn
+// CHECK-NEXT: Type: SHT_REL
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[RELADDR:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: [[RELSIZE:.*]]
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize: [[RELENT:.*]]
+
+// CHECK:        Name: .dynamic
+// CHECK-NEXT:   Type: SHT_DYNAMIC
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     SHF_ALLOC
+// CHECK-NEXT:     SHF_WRITE
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Address: [[ADDR:.*]]
+// CHECK-NEXT:   Offset: [[OFFSET:.*]]
+// CHECK-NEXT:   Size: [[SIZE:.*]]
+// CHECK-NEXT:   Link: [[DYNSTR]]
+// CHECK-NEXT:   Info: 0
+// CHECK-NEXT:   AddressAlignment: [[ALIGN:.*]]
+// CHECK-NEXT:   EntrySize: 8
+// CHECK-NEXT:   SectionData (
+// CHECK:        )
+
+// CHECK:      Name: .symtab
+// CHECK-NEXT: Type: SHT_SYMTAB
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize: [[SYMENT:.*]]
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value: 0x12000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start@
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Non
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed@
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// DONT_EXPORT:      DynamicSymbols [
+// DONT_EXPORT-NEXT:   Symbol {
+// DONT_EXPORT-NEXT:     Name: @
+// DONT_EXPORT-NEXT:     Value: 0x0
+// DONT_EXPORT-NEXT:     Size: 0
+// DONT_EXPORT-NEXT:     Binding: Local (0x0)
+// DONT_EXPORT-NEXT:     Type: None (0x0)
+// DONT_EXPORT-NEXT:     Other: 0
+// DONT_EXPORT-NEXT:     Section: Undefined (0x0)
+// DONT_EXPORT-NEXT:   }
+// DONT_EXPORT-NEXT:   Symbol {
+// DONT_EXPORT-NEXT:     Name: bar@
+// DONT_EXPORT-NEXT:     Value: 0x0
+// DONT_EXPORT-NEXT:     Size: 0
+// DONT_EXPORT-NEXT:     Binding: Global
+// DONT_EXPORT-NEXT:     Type: Function
+// DONT_EXPORT-NEXT:     Other: 0
+// DONT_EXPORT-NEXT:     Section: Undefined
+// DONT_EXPORT-NEXT:   }
+// DONT_EXPORT-NEXT:   Symbol {
+// DONT_EXPORT-NEXT:     Name: zed@
+// DONT_EXPORT-NEXT:     Value: 0x0
+// DONT_EXPORT-NEXT:     Size: 0
+// DONT_EXPORT-NEXT:     Binding: Global
+// DONT_EXPORT-NEXT:     Type: None
+// DONT_EXPORT-NEXT:     Other: 0
+// DONT_EXPORT-NEXT:     Section: Undefined
+// DONT_EXPORT-NEXT:   }
+// DONT_EXPORT-NEXT: ]
+
+// CHECK:      DynamicSection [
+// CHECK-NEXT:   Tag        Type                 Name/Value
+// CHECK-NEXT:   0x0000001D RUNPATH              foo:bar
+// CHECK-NEXT:   0x00000001 NEEDED               Shared library: [{{.*}}2.so]
+// CHECK-NEXT:   0x00000015 DEBUG                0x0
+// CHECK-NEXT:   0x00000011 REL                  [[RELADDR]]
+// CHECK-NEXT:   0x00000012 RELSZ                [[RELSIZE]] (bytes)
+// CHECK-NEXT:   0x00000013 RELENT               [[RELENT]] (bytes)
+// CHECK-NEXT:   0x00000006 SYMTAB               [[DYNSYMADDR]]
+// CHECK-NEXT:   0x0000000B SYMENT               [[SYMENT]] (bytes)
+// CHECK-NEXT:   0x00000005 STRTAB               [[DYNSTRADDR]]
+// CHECK-NEXT:   0x0000000A STRSZ
+// CHECK-NEXT:   0x00000004 HASH                 [[HASHADDR]]
+// CHECK-NEXT:   0x00000000 NULL                 0x0
+// CHECK-NEXT: ]
+
+// CHECK:     ProgramHeaders [
+// CHECK:        Type: PT_INTERP
+// CHECK-NEXT:   Offset: [[INTERPOFFSET]]
+// CHECK-NEXT:   VirtualAddress: [[INTERPADDR]]
+// CHECK-NEXT:   PhysicalAddress: [[INTERPADDR]]
+// CHECK-NEXT:   FileSize: [[INTERPSIZE]]
+// CHECK-NEXT:   MemSize: [[INTERPSIZE]]
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     PF_R
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Alignment: 1
+// CHECK-NEXT: }
+// CHECK:        Type: PT_DYNAMIC
+// CHECK-NEXT:   Offset: [[OFFSET]]
+// CHECK-NEXT:   VirtualAddress: [[ADDR]]
+// CHECK-NEXT:   PhysicalAddress: [[ADDR]]
+// CHECK-NEXT:   FileSize: [[SIZE]]
+// CHECK-NEXT:   MemSize: [[SIZE]]
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     PF_R
+// CHECK-NEXT:     PF_W
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Alignment: [[ALIGN]]
+// CHECK-NEXT: }
+
+// CHECK:      HashTable {
+// CHECK-NEXT:   Num Buckets: 4
+// CHECK-NEXT:   Num Chains: 4
+// CHECK-NEXT:   Buckets: [3, 0, 2, 0]
+// CHECK-NEXT:   Chains: [0, 0, 0, 1]
+// CHECK-NEXT: }
+
+.global _start
+_start:
+.long bar@GOT
+.long zed@GOT
diff --git a/test/ELF/shf-info-link.test b/test/ELF/shf-info-link.test
new file mode 100644 (file)
index 0000000..ea15655
--- /dev/null
@@ -0,0 +1,32 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: yaml2obj %S/Inputs/shf-info-link.test  -o %t2.o
+# RUN: ld.lld %t.o %t2.o -o %t3.o -r
+# RUN: llvm-readobj -s %t3.o | FileCheck %s
+
+# CHECK-NOT: Name: .rela.text
+# CHECK:     Name: .rela.text
+# CHECK-NOT: Name: .rela.text
+
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          foo
+        Type:            R_X86_64_64
+Symbols:
+  Global:
+    - Name:            foo
diff --git a/test/ELF/sht-group-gold-r.test b/test/ELF/sht-group-gold-r.test
new file mode 100644 (file)
index 0000000..3a3889e
--- /dev/null
@@ -0,0 +1,17 @@
+# GNU gold 1.14 (the newest version as of July 2017) seems to create
+# non-standard-compliant SHT_GROUP sections when the -r option is given.
+#
+# Such SHT_GROUP sections use section names as their signatures
+# instead of symbols pointed by sh_link field. Since it is prevalent,
+# we accept such nonstandard sections.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %p/Inputs/sht-group-gold-r.elf %t.o -o %t.exe
+# RUN: llvm-objdump -t %t.exe | FileCheck %s
+
+# CHECK: .text 00000000 bar
+# CHECK: .text 00000000 foo
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/soname.s b/test/ELF/soname.s
new file mode 100644 (file)
index 0000000..a26bb30
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -shared -soname=bar -o %t.so
+// RUN: ld.lld %t.o -shared --soname=bar -o %t2.so
+// RUN: ld.lld %t.o %t.so %t2.so -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s
+
+// CHECK:  0x0000000000000001 NEEDED               Shared library: [bar]
+// CHECK-NOT: NEEDED
+
+.global _start
+_start:
diff --git a/test/ELF/soname2.s b/test/ELF/soname2.s
new file mode 100644 (file)
index 0000000..9fb8da5
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -shared -soname=foo.so -o %t
+// RUN: llvm-readobj --dynamic-table %t | FileCheck %s
+
+// CHECK: 0x000000000000000E SONAME  Library soname: [foo.so]
+
+.global _start
+_start:
diff --git a/test/ELF/sort-norosegment.s b/test/ELF/sort-norosegment.s
new file mode 100644 (file)
index 0000000..c5a759a
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+
+# RUN: ld.lld -no-rosegment -o %t1  %t -shared
+# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s
+
+# CHECK:      .text    {{.*}}   AX
+# CHECK-NEXT: .dynsym  {{.*}}   A
+# CHECK-NEXT: .hash    {{.*}}   A
+# CHECK-NEXT: .dynstr  {{.*}}   A
+# CHECK-NEXT: foo      {{.*}}  WA
+# CHECK-NEXT: .dynamic {{.*}}  WA
+
+.section foo, "aw"
+.byte 0
diff --git a/test/ELF/splitstacks.s b/test/ELF/splitstacks.s
new file mode 100644 (file)
index 0000000..3b7e67e
--- /dev/null
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: not ld.lld %t1.o -o %t 2>&1 | FileCheck %s
+# CHECK: .o: object file compiled with -fsplit-stack is not supported
+
+.globl _start
+_start:
+ nop
+
+.section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/start-lib-comdat.s b/test/ELF/start-lib-comdat.s
new file mode 100644 (file)
index 0000000..ce03959
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
+// RUN:   %p/Inputs/start-lib-comdat.s -o %t2.o
+// RUN: ld.lld -shared -o %t3 %t1.o --start-lib %t2.o --end-lib
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+// RUN: ld.lld -shared -o %t3 --start-lib %t2.o --end-lib %t1.o
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+
+// CHECK:      Name: zed
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type:
+// CHECK-NEXT: Other:
+// CHECK-NEXT: Section: Undefined
+
+        call bar@plt
+// The other file also has a section in the zed comdat, but it defines the
+// symbol zed. That means that we will have a lazy symbol zed, but when adding
+// the actual file zed will be undefined.
+        .section        .sec,"aG",@progbits,zed,comdat
diff --git a/test/ELF/start-lib.s b/test/ELF/start-lib.s
new file mode 100644 (file)
index 0000000..013a2b2
--- /dev/null
@@ -0,0 +1,25 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/start-lib1.s -o %t2.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/start-lib2.s -o %t3.o
+
+// RUN: ld.lld -o %t3 %t1.o %t2.o %t3.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST1 %s
+// TEST1: Name: bar
+// TEST1: Name: foo
+
+// RUN: ld.lld -o %t3 %t1.o -u bar --start-lib %t2.o %t3.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST2 %s
+// TEST2: Name: bar
+// TEST2-NOT: Name: foo
+
+// RUN: ld.lld -o %t3 %t1.o --start-lib %t2.o %t3.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST3 %s
+// TEST3-NOT: Name: bar
+// TEST3-NOT: Name: foo
+
+.globl _start
+_start:
diff --git a/test/ELF/startstop-gccollect.s b/test/ELF/startstop-gccollect.s
new file mode 100644 (file)
index 0000000..daff081
--- /dev/null
@@ -0,0 +1,34 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Default run: sections foo and bar exist in output
+# RUN: ld.lld %t -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+
+## Check that foo and bar sections are not garbage collected,
+## we do not want to reclaim sections if they are referred
+## by __start_* and __stop_* symbols.
+# RUN: ld.lld %t --gc-sections -o %tout
+# RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+
+# DISASM:      _start:
+# DISASM-NEXT: 201000:        e8 05 00 00 00  callq   5 <__start_foo>
+# DISASM-NEXT: 201005:        e8 01 00 00 00  callq   1 <__start_bar>
+# DISASM-NEXT: Disassembly of section foo:
+# DISASM-NEXT: __start_foo:
+# DISASM-NEXT: 20100a:        90      nop
+# DISASM-NEXT: Disassembly of section bar:
+# DISASM-NEXT: __start_bar:
+# DISASM-NEXT: 20100b:        90      nop
+
+.global _start
+.text
+_start:
+ callq __start_foo
+ callq __start_bar
+
+.section foo,"ax"
+ nop
+
+.section bar,"ax"
+ nop
diff --git a/test/ELF/startstop-shared.s b/test/ELF/startstop-shared.s
new file mode 100644 (file)
index 0000000..80ccf3d
--- /dev/null
@@ -0,0 +1,28 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -t %t.so | FileCheck  %s
+
+        .data
+        .quad __start_foo
+        .section foo,"aw"
+
+        .hidden __start_bar
+        .quad __start_bar
+        .section bar,"a"
+
+// Test that we are able to hide the symbol.
+// CHECK:      R_X86_64_RELATIVE - 0x[[ADDR:.*]]
+
+// By default the symbol is visible and we need a dynamic reloc.
+// CHECK:  R_X86_64_64 __start_foo 0x0
+
+// CHECK:      Name: __start_bar
+// CHECK-NEXT: Value: 0x[[ADDR]]
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Local
+
+// CHECK:      Name: __start_foo
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Global
diff --git a/test/ELF/startstop-shared2.s b/test/ELF/startstop-shared2.s
new file mode 100644 (file)
index 0000000..b8bd8ab
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/startstop-shared2.s -o %t.o
+// RUN: ld.lld -o %t.so %t.o -shared
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
+// RUN: ld.lld -o %t %t2.o %t.so
+// RUN: llvm-objdump -s -h %t | FileCheck %s
+
+// CHECK: foo           00000000 0000000000201008
+
+// CHECK: Contents of section .text:
+// CHECK-NEXT: 201000 08102000 00000000
+
+.quad __start_foo
+.section foo,"ax"
diff --git a/test/ELF/startstop.s b/test/ELF/startstop.s
new file mode 100644 (file)
index 0000000..250fb2c
--- /dev/null
@@ -0,0 +1,91 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout -shared
+// RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s
+// RUN: llvm-readobj -symbols -r %tout | FileCheck -check-prefix=SYMBOL %s
+
+// DISASM: _start:
+// DISASM:    1000:       {{.*}}  callq   10
+// DISASM:    1005:       {{.*}}  callq   8
+// DISASM:    100a:       {{.*}}  callq   3
+// DISASM: Disassembly of section foo:
+// DISASM: __start_foo:
+// DISASM:    100f:       90      nop
+// DISASM:    1010:       90      nop
+// DISASM:    1011:       90      nop
+// DISASM: Disassembly of section bar:
+// DISASM: __start_bar:
+// DISASM:    1012:       90      nop
+// DISASM:    1013:       90      nop
+// DISASM:    1014:       90      nop
+
+
+// SYMBOL:      Relocations [
+// SYMBOL-NEXT:   Section ({{.*}}) .rela.dyn {
+// SYMBOL-NEXT:     0x2010 R_X86_64_64 __stop_zed1 0x0
+// SYMBOL-NEXT:     0x2018 R_X86_64_64 __stop_zed1 0x1
+// SYMBOL-NEXT:     0x2000 R_X86_64_64 __stop_zed2 0x0
+// SYMBOL-NEXT:     0x2008 R_X86_64_64 __stop_zed2 0x1
+// SYMBOL-NEXT:   }
+// SYMBOL-NEXT: ]
+
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __start_bar
+// SYMBOL:   Value: 0x1012
+// SYMBOL:   STV_HIDDEN
+// SYMBOL:   Section: bar
+// SYMBOL: }
+// SYMBOL-NOT:   Section: __stop_bar
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __start_foo
+// SYMBOL:   Value: 0x100F
+// SYMBOL:   STV_HIDDEN
+// SYMBOL:   Section: foo
+// SYMBOL: }
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __stop_foo
+// SYMBOL:   Value: 0x1012
+// STMBOL:   STV_HIDDEN
+// SYMBOL:   Section: foo
+// SYMBOL: }
+
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __stop_zed1
+// SYMBOL:   Value: 0x2010
+// STMBOL:   Other: 0
+// SYMBOL:   Section: zed1
+// SYMBOL: }
+// SYMBOL: Symbol {
+// SYMBOL:   Name: __stop_zed2
+// SYMBOL:   Value: 0x2020
+// STMBOL:   Other: 0
+// SYMBOL:   Section: zed2
+// SYMBOL: }
+
+.hidden __start_foo
+.hidden __stop_foo
+.hidden __start_bar
+.global _start
+.text
+_start:
+       call __start_foo
+       call __stop_foo
+       call __start_bar
+
+.section foo,"ax"
+       nop
+       nop
+       nop
+
+.section bar,"ax"
+       nop
+       nop
+       nop
+
+.section zed1, "aw"
+        .quad __stop_zed2
+        .quad __stop_zed2 + 1
+
+.section zed2, "aw"
+        .quad __stop_zed1
+        .quad __stop_zed1 + 1
diff --git a/test/ELF/static-with-export-dynamic.s b/test/ELF/static-with-export-dynamic.s
new file mode 100644 (file)
index 0000000..8634835
--- /dev/null
@@ -0,0 +1,32 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-cloudabi %s -o %t.o
+// RUN: ld.lld --export-dynamic %t.o -o %t
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+// REQUIRES: x86
+
+// Ensure that a dynamic symbol table is present when --export-dynamic
+// is passed in, even when creating statically linked executables.
+//
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x11000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+  ret
diff --git a/test/ELF/string-gc.s b/test/ELF/string-gc.s
new file mode 100644 (file)
index 0000000..3157a79
--- /dev/null
@@ -0,0 +1,73 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t --gc-sections
+// RUN: llvm-readobj -symbols %t | FileCheck %s
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: s3
+// CHECK-NEXT:     Value: 0x200125
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: Object (0x1)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .rodata (0x1)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: s1
+// CHECK-NEXT:     Value: 0x200120
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: Object (0x1)
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN (0x2)
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .rodata (0x1)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x201000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: Function (0x2)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text (0x2)
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.text
+.globl _start
+.type _start,@function
+_start:
+movl $s1, %eax
+movl $s3, %eax
+
+.hidden s1
+.type s1,@object
+.section .rodata.str1.1,"aMS",@progbits,1
+.globl s1
+s1:
+.asciz "abcd"
+
+.hidden s2
+.type s2,@object
+.globl s2
+s2:
+.asciz "efgh"
+
+.type s3,@object
+s3:
+.asciz "ijkl"
+
+.type s4,@object
+.globl s4
+s4:
+.asciz "mnop"
diff --git a/test/ELF/string-table.s b/test/ELF/string-table.s
new file mode 100644 (file)
index 0000000..490c4d5
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -sections %t2 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+
+.section        foobar,"",@progbits
+
+.section bar, "a"
+
+// Both sections are in the output and that the alloc section is first:
+// CHECK:      Name: bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:  SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x200120
+
+// CHECK:      Name: foobar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x0
+
+// CHECK-NOT:  Name: foobar
diff --git a/test/ELF/strip-all.s b/test/ELF/strip-all.s
new file mode 100644 (file)
index 0000000..f322119
--- /dev/null
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix BEFORE
+#BEFORE:       .symtab
+#BEFORE-NEXT:  .shstrtab
+#BEFORE-NEXT:  .strtab
+
+#RUN: ld.lld %t.o --strip-all -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix AFTER
+#AFTER-NOT: .symtab
+#AFTER:     .shstrtab
+#AFTER-NOT: .strtab
+
+# Ignore --strip-all if -r is specified
+#RUN: ld.lld %t.o --strip-all -r -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix BEFORE
+
+# Test alias -s
+#RUN: ld.lld %t.o -s -o %t1
+#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix AFTER
+
+# exits with return code 42 on linux
+.globl _start
+_start:
+  mov $60, %rax
+  mov $42, %rdi
+  syscall
diff --git a/test/ELF/strip-debug.s b/test/ELF/strip-debug.s
new file mode 100644 (file)
index 0000000..81f7572
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -g %s -o %t
+# RUN: ld.lld %t -o %t2
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=DEFAULT %s
+# RUN: ld.lld %t -o %t2 --strip-debug
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=STRIP %s
+# RUN: ld.lld %t -o %t2 -S
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=STRIP %s
+# RUN: ld.lld %t -o %t2 --strip-all
+# RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=STRIP %s
+
+# DEFAULT: Name: .debug_info
+# DEFAULT: Name: .debug_abbrev
+# DEFAULT: Name: .debug_aranges
+# DEFAULT: Name: .debug_line
+
+# STRIP-NOT: Name: .debug_info
+# STRIP-NOT: Name: .debug_abbrev
+# STRIP-NOT: Name: .debug_aranges
+# STRIP-NOT: Name: .debug_line
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/symbol-ordering-file.s b/test/ELF/symbol-ordering-file.s
new file mode 100644 (file)
index 0000000..5a88b8c
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.out
+# RUN: llvm-objdump -s %t.out| FileCheck %s --check-prefix=BEFORE
+
+# BEFORE:      Contents of section .foo:
+# BEFORE-NEXT:  201000 11223344 5566
+
+# RUN: echo "_foo4  " > %t_order.txt
+# RUN: echo "  _foo3" >> %t_order.txt
+# RUN: echo "_foo5" >> %t_order.txt
+# RUN: echo "_foo2" >> %t_order.txt
+# RUN: echo " " >> %t_order.txt
+# RUN: echo "_foo4" >> %t_order.txt
+# RUN: echo "_bar1" >> %t_order.txt
+# RUN: echo "_foo1" >> %t_order.txt
+
+# RUN: ld.lld --symbol-ordering-file %t_order.txt %t.o -o %t2.out
+# RUN: llvm-objdump -s %t2.out| FileCheck %s --check-prefix=AFTER
+
+# AFTER:      Contents of section .foo:
+# AFTER-NEXT:  201000 44335566 2211
+
+.section .foo,"ax",@progbits,unique,1
+_foo1:
+ .byte 0x11
+
+.section .foo,"ax",@progbits,unique,2
+_foo2:
+ .byte 0x22
+
+.section .foo,"ax",@progbits,unique,3
+_foo3:
+ .byte 0x33
+
+.section .foo,"ax",@progbits,unique,4
+_foo4:
+ .byte 0x44
+
+.section .foo,"ax",@progbits,unique,5
+_foo5:
+ .byte 0x55
+_bar1:
+ .byte 0x66
diff --git a/test/ELF/symbol-override.s b/test/ELF/symbol-override.s
new file mode 100644 (file)
index 0000000..8b62d87
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/symbol-override.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t1.o %t2.so -o %t
+// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: do
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value: 0x201000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.text
+.globl foo
+.type foo,@function
+foo:
+nop
+
+.text
+.globl _start
+_start:
+callq do@plt
diff --git a/test/ELF/symbols.s b/test/ELF/symbols.s
new file mode 100644 (file)
index 0000000..54dfcbd
--- /dev/null
@@ -0,0 +1,188 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -symbols -sections %t2 | FileCheck %s
+// REQUIRES: x86
+
+.type _start, @function
+.globl _start
+_start:
+
+.type foo, @object
+.weak foo
+foo:
+
+.type bar, @object
+.weak bar
+.long bar
+
+.section        foobar,"a",@nobits,unique,1
+.globl zed
+zed:
+        .long 0
+.globl zed2
+zed2:
+.long 0
+
+.section        foobar,"a",@nobits,unique,2
+.globl zed3
+.size zed3, 4
+zed3:
+
+.globl abs
+abs = 0x123
+
+.comm common,4,4
+
+.global protected
+.protected protected
+protected:
+
+.global hidden
+.hidden hidden
+hidden:
+
+.global internal
+.internal internal
+internal:
+
+// CHECK:      Name: foobar
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x200158
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x201000
+
+// CHECK:      Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x202000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:  (0)
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local (0x0)
+// CHECK-NEXT:     Type: None (0x0)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:     Name: hidden
+// CHECK-NEXT:     Value: 0x200160
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: internal
+// CHECK-NEXT:     Value: 0x200160
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x1)
+// CHECK-NEXT:       STV_INTERNAL
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _start
+// CHECK-NEXT:     Value: 0x201000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: Function
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: abs
+// CHECK-NEXT:     Value: 0x123
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Absolute
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: bar
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak (0x2)
+// CHECK-NEXT:     Type: Object (0x1)
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined (0x0)
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: common
+// CHECK-NEXT:     Value: 0x202000
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .bss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: foo
+// CHECK-NEXT:     Value: 0x201000
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Weak (0x2)
+// CHECK-NEXT:     Type: Object
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected
+// CHECK-NEXT:     Value: 0x200160
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x3)
+// CHECK-NEXT:       STV_PROTECTED
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed
+// CHECK-NEXT:     Value: 0x200158
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global (0x1)
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed2
+// CHECK-NEXT:     Value: 0x20015C
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: zed3
+// CHECK-NEXT:     Value: 0x200160
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: foobar
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/symver-archive.s b/test/ELF/symver-archive.s
new file mode 100644 (file)
index 0000000..be50503
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1
+# RUN: rm -f %t.a
+# RUN: llvm-ar rcs %t.a %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive1.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive2.s -o %t3.o
+# RUN: ld.lld -o %t.out %t2.o %t3.o %t.a
+
+.text
+.globl x
+.type x, @function
+x:
+
+.globl xx
+xx = x
diff --git a/test/ELF/synthetic-got.s b/test/ELF/synthetic-got.s
new file mode 100644 (file)
index 0000000..8d82f31
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { }" > %t0.script
+# RUN: ld.lld -shared %t.o -o %t0.out --script %t0.script
+# RUN: llvm-objdump -section-headers %t0.out | FileCheck %s --check-prefix=GOT
+# RUN: llvm-objdump -s -section=.got -section=.got.plt %t0.out \
+# RUN:   | FileCheck %s --check-prefix=GOTDATA
+
+# GOT:     Sections:
+# GOT:      8  .got.plt     00000020 00000000000000e0 DATA
+# GOT:      10 .got         00000008 00000000000001d0 DATA
+# GOTDATA:     Contents of section .got.plt:
+# GOTDATA-NEXT:  00e0 00010000 00000000 00000000 00000000
+# GOTDATA-NEXT:  00f0 00000000 00000000 d6000000 00000000
+# GOTDATA-NEXT: Contents of section .got:
+# GOTDATA-NEXT:  01d0 00000000 00000000
+
+# RUN: echo "SECTIONS { .mygot : { *(.got) *(.got.plt) } }" > %t1.script
+# RUN: ld.lld -shared %t.o -o %t1.out --script %t1.script
+# RUN: llvm-objdump -section-headers %t1.out | FileCheck %s --check-prefix=MYGOT
+# RUN: llvm-objdump -s -section=.mygot %t1.out | FileCheck %s --check-prefix=MYGOTDATA
+
+# MYGOT:     Sections:
+# MYGOT:      8  .mygot     00000028 00000000000000e0 DATA
+# MYGOT-NOT:  .got
+# MYGOT-NOT:  .got.plt
+# MYGOTDATA:      00e0 00000000 00000000 08010000 00000000
+# MYGOTDATA-NEXT: 00f0 00000000 00000000 00000000 00000000
+# MYGOTDATA-NEXT: 0100 d6000000 00000000
+
+mov bar@gotpcrel(%rip), %rax
+call foo@plt
diff --git a/test/ELF/sysroot.s b/test/ELF/sysroot.s
new file mode 100644 (file)
index 0000000..358b4d9
--- /dev/null
@@ -0,0 +1,38 @@
+// RUN: mkdir -p %t/lib
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t/m.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:     %p/Inputs/libsearch-st.s -o %t/st.o
+// RUN: rm -f %t/lib/libls.a
+// RUN: llvm-ar rcs %t/lib/libls.a %t/st.o
+// REQUIRES: x86
+
+// Should not link because of undefined symbol _bar
+// RUN: not ld.lld -o %t/r %t/m.o 2>&1 \
+// RUN:     | FileCheck --check-prefix=UNDEFINED %s
+// UNDEFINED: error: undefined symbol: _bar
+// UNDEFINED: >>> referenced by {{.*}}:(.text+0x1)
+
+// We need to be sure that there is no suitable library in the /lib directory
+// RUN: not ld.lld -o %t/r %t/m.o -L/lib -l:libls.a 2>&1 \
+// RUN:     | FileCheck --check-prefix=NOLIB %s
+// NOLIB: unable to find library -l:libls.a
+
+// Should just remove the '=' symbol if --sysroot is not specified.
+// Case 1: relative path
+// RUN: cd %t && ld.lld -o %t/r %t/m.o -L=lib -l:libls.a
+// Case 2: absolute path
+// RUN: cd %p && ld.lld -o %t/r %t/m.o -L=%t/lib -l:libls.a
+
+// RUN: cd %p
+
+// Should substitute SysRoot if specified
+// RUN: ld.lld -o %t/r %t/m.o --sysroot=%t -L=lib -l:libls.a
+// RUN: ld.lld -o %t/r %t/m.o --sysroot=%t -L=/lib -l:libls.a
+
+// Should not substitute SysRoot if the directory name does not start with '='
+// RUN: not ld.lld -o %t/r %r/m.o --sysroot=%t -Llib -l:libls.a
+// RUN: not ld.lld -o %t/r %r/m.o --sysroot=%t -L/lib -l:libls.a
+
+.globl _start,_bar
+_start:
+  call _bar
diff --git a/test/ELF/tail-merge-string-align.s b/test/ELF/tail-merge-string-align.s
new file mode 100644 (file)
index 0000000..a5d4603
--- /dev/null
@@ -0,0 +1,35 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared -O3
+// RUN: llvm-readobj -s -section-data %t.so | FileCheck %s
+
+        .section        .rodata.4a,"aMS",@progbits,1
+        .align 4
+        .asciz "abcdef"
+
+        .section        .rodata.4b,"aMS",@progbits,1
+        .align 4
+        .asciz "ef"
+
+        .section        .rodata.4c,"aMS",@progbits,1
+        .align 4
+        .asciz "f"
+
+
+// CHECK:      Name: .rodata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT:   SHF_STRINGS
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 1
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000:    61626364 65660000 6600               |abcdef..f.|
+// CHECK-NEXT: )
diff --git a/test/ELF/tls-align.s b/test/ELF/tls-align.s
new file mode 100644 (file)
index 0000000..56b404e
--- /dev/null
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout -shared
+// RUN: llvm-readobj -program-headers %tout | FileCheck %s
+
+        .section        .tbss,"awT",@nobits
+        .align  8
+        .long   0
+
+// CHECK:      ProgramHeader {
+// CHECK:        Type: PT_TLS
+// CHECK-NEXT:   Offset:
+// CHECK-NEXT:   VirtualAddress:
+// CHECK-NEXT:   PhysicalAddress:
+// CHECK-NEXT:   FileSize: 0
+// CHECK-NEXT:   MemSize: 8
+// CHECK-NEXT:   Flags [
+// CHECK-NEXT:     PF_R (0x4)
+// CHECK-NEXT:   ]
+// CHECK-NEXT:   Alignment: 8
+// CHECK-NEXT: }
diff --git a/test/ELF/tls-archive.s b/test/ELF/tls-archive.s
new file mode 100644 (file)
index 0000000..9a88fdd
--- /dev/null
@@ -0,0 +1,10 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-mismatch.s -o %t2
+// RUN: rm -f %t.a
+// RUN: llvm-ar cru %t.a %t2
+// RUN: ld.lld %t.a %t -o %t3
+
+.globl _start,tlsvar
+_start:
+  movq tlsvar@GOTTPOFF(%rip),%rdx
diff --git a/test/ELF/tls-dynamic-i686.s b/test/ELF/tls-dynamic-i686.s
new file mode 100644 (file)
index 0000000..ac88e6e
--- /dev/null
@@ -0,0 +1,99 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %tout
+// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.type  tls2,@object
+.globl tls2
+.hidden tls2
+.align 4
+tls2:
+ .long 0
+ .size tls2, 8
+
+.section .text
+.globl _start
+_start:
+leal tls0@tlsgd(,%ebx,1),%eax
+call __tls_get_addr@plt
+
+leal tls1@tlsgd(,%ebx,1),%eax
+call __tls_get_addr@plt
+
+leal tls2@tlsldm(%ebx),%eax
+call __tls_get_addr@plt
+leal tls2@dtpoff(%eax),%edx
+
+leal tls2@tlsldm(%ebx),%eax
+call __tls_get_addr@plt
+leal tls2@dtpoff+4(%eax),%edx
+
+movl %gs:0,%eax
+addl tls0@gotntpoff(%ebx),%eax
+
+movl %gs:0,%eax
+addl tls1@gotntpoff(%ebx),%eax
+
+// CHECK:      Name: .got (
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x3068
+// CHECK-NEXT: Offset: 0x3068
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+
+// CHECK: Relocations [
+// CHECK:      Section ({{.+}}) .rel.dyn {
+// CHECK-NEXT: 0x3078 R_386_TLS_DTPMOD32 - 0x0
+// CHECK-NEXT: 0x3068 R_386_TLS_DTPMOD32 tls0 0x0
+// CHECK-NEXT: 0x306C R_386_TLS_DTPOFF32 tls0 0x0
+// CHECK-NEXT: 0x3080 R_386_TLS_TPOFF tls0 0x0
+// CHECK-NEXT: 0x3070 R_386_TLS_DTPMOD32 tls1 0x0
+// CHECK-NEXT: 0x3074 R_386_TLS_DTPOFF32 tls1 0x0
+// CHECK-NEXT: 0x3084 R_386_TLS_TPOFF tls1 0x0
+// CHECK-NEXT: }
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: _start:
+// General dynamic model:
+// -32 and -24 are first and second GOT entries offsets.
+// Each one is a pair of records.
+// DIS-NEXT: 1000: 8d 04 1d e0 ff ff ff  leal -32(,%ebx), %eax
+// DIS-NEXT: 1007: e8 64 00 00 00        calll 100
+// DIS-NEXT: 100c: 8d 04 1d e8 ff ff ff  leal -24(,%ebx), %eax
+// DIS-NEXT: 1013: e8 58 00 00 00        calll 88
+// Local dynamic model:
+// -16 is a local module tls index offset.
+// DIS-NEXT: 1018: 8d 83 f0 ff ff ff leal -16(%ebx), %eax
+// DIS-NEXT: 101e: e8 4d 00 00 00    calll 77
+// DIS-NEXT: 1023: 8d 90 08 00 00 00 leal 8(%eax), %edx
+// DIS-NEXT: 1029: 8d 83 f0 ff ff ff leal -16(%ebx), %eax
+// DIS-NEXT: 102f: e8 3c 00 00 00    calll 60
+// DIS-NEXT: 1034: 8d 90 0c 00 00 00 leal 12(%eax), %edx
+// Initial exec model:
+// DIS-NEXT: 103a: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DIS-NEXT: 1040: 03 83 f8 ff ff ff addl -8(%ebx), %eax
+// DIS-NEXT: 1046: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DIS-NEXT: 104c: 03 83 fc ff ff ff addl -4(%ebx), %eax
diff --git a/test/ELF/tls-dynamic.s b/test/ELF/tls-dynamic.s
new file mode 100644 (file)
index 0000000..05473d4
--- /dev/null
@@ -0,0 +1,87 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld -shared %t -o %tout
+// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+  leaq  a@tlsld(%rip), %rdi
+  callq __tls_get_addr@PLT
+  leaq  b@tlsld(%rip), %rdi
+  callq __tls_get_addr@PLT
+  leaq  a@dtpoff(%rax), %rcx
+  leaq  b@dtpoff(%rax), %rcx
+  .long b@dtpoff, 0
+  leaq  c@tlsgd(%rip), %rdi
+  rex64
+  callq __tls_get_addr@PLT
+  leaq  a@dtpoff(%rax), %rcx
+  // Initial Exec Model Code Sequence, II
+  movq c@gottpoff(%rip),%rax
+  movq %fs:(%rax),%rax
+  movabs $a@dtpoff, %rax
+  movabs $b@dtpoff, %rax
+  movabs $a@dtpoff, %rax
+
+  .global a
+  .hidden a
+  .section .tbss,"awT",@nobits
+  .align 4
+a:
+  .long 0
+
+  .section .tbss,"awT",@nobits
+  .align 4
+b:
+  .long 0
+  .global c
+  .section .tbss,"awT",@nobits
+  .align 4
+c:
+  .long 0
+
+// Get the address of the got, and check that it has 4 entries.
+
+// CHECK:      Sections [
+// CHECK:          Name: .got (
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x30D0
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 40
+
+// CHECK:      Relocations [
+// CHECK:        Section ({{.+}}) .rela.dyn {
+// CHECK-NEXT:     0x30D0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT:     0x30E0 R_X86_64_DTPMOD64 c 0x0
+// CHECK-NEXT:     0x30E8 R_X86_64_DTPOFF64 c 0x0
+// CHECK-NEXT:     0x30F0 R_X86_64_TPOFF64 c 0x0
+// CHECK-NEXT:   }
+
+// 4297 = (0x20D0 + -4) - (0x1000 + 3) // PC relative offset to got entry.
+// 4285 = (0x20D0 + -4) - (0x100c + 3) // PC relative offset to got entry.
+// 4267 = (0x20E0 + -4) - (0x102e + 3) // PC relative offset to got entry.
+// 4263 = (0x20F0 + -4) - (0x1042 + 3) // PC relative offset to got entry.
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: .text:
+// DIS-NEXT:     1000: {{.+}} leaq    8393(%rip), %rdi
+// DIS-NEXT:     1007: {{.+}} callq
+// DIS-NEXT:     100c: {{.+}} leaq    8381(%rip), %rdi
+// DIS-NEXT:     1013: {{.+}} callq
+// DIS-NEXT:     1018: {{.+}} leaq    (%rax), %rcx
+// DIS-NEXT:     101f: {{.+}} leaq    4(%rax), %rcx
+// DIS-NEXT:     1026: 04 00
+// DIS-NEXT:     1028: 00 00
+// DIS-NEXT:     102a: 00 00
+// DIS-NEXT:     102c: 00 00
+// DIS-NEXT:     102e: {{.+}} leaq    8363(%rip), %rdi
+// DIS-NEXT:     1035: {{.+}} callq
+// DIS-NEXT:     103b: {{.+}} leaq    (%rax), %rcx
+// DIS-NEXT:     1042: {{.+}} movq    8359(%rip), %rax
+// DIS-NEXT:     1049: {{.+}} movq    %fs:(%rax), %rax
+// DIS-NEXT:     104d: {{.+}} movabsq $0, %rax
+// DIS-NEXT:     1057: {{.+}} movabsq $4, %rax
+// DIS-NEXT:     1061: {{.+}} movabsq $0, %rax
diff --git a/test/ELF/tls-error.s b/test/ELF/tls-error.s
new file mode 100644 (file)
index 0000000..b617899
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+// CHECK: R_X86_64_TPOFF32 out of range
+
+.global _start
+_start:
+        movl %fs:a@tpoff, %eax
+.global a
+.section        .tbss,"awT",@nobits
+a:
+.zero 0x80000001
diff --git a/test/ELF/tls-got-entry.s b/test/ELF/tls-got-entry.s
new file mode 100644 (file)
index 0000000..c7b9669
--- /dev/null
@@ -0,0 +1,25 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-got-entry.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck %s
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     R_X86_64_TPOFF64 tlsshared0 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.globl _start
+_start:
+ .byte 0x66
+ leaq tlsshared0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ .byte 0x66
+ leaq tlsshared0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
diff --git a/test/ELF/tls-got.s b/test/ELF/tls-got.s
new file mode 100644 (file)
index 0000000..450dd63
--- /dev/null
@@ -0,0 +1,58 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-got.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld -e main %t1.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r %t3 | FileCheck %s
+// RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM %s
+
+// CHECK:      Section {
+// CHECK:      Index: 8
+// CHECK-NEXT: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[ADDR:.*]]
+// CHECK-NEXT: Offset: 0x20B0
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: }
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     0x2020B8 R_X86_64_TPOFF64 tls0 0x0
+// CHECK-NEXT:     [[ADDR]] R_X86_64_TPOFF64 tls1 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+//0x201000 + 4249 + 7 = 0x2020B0
+//0x20100A + 4247 + 7 = 0x2020B8
+//0x201014 + 4237 + 7 = 0x2020B8
+//DISASM:      Disassembly of section .text:
+//DISASM-NEXT: main:
+//DISASM-NEXT: 201000: 48 8b 05 a9 10 00 00 movq 4265(%rip), %rax
+//DISASM-NEXT: 201007: 64 8b 00 movl %fs:(%rax), %eax
+//DISASM-NEXT: 20100a: 48 8b 05 a7 10 00 00 movq 4263(%rip), %rax
+//DISASM-NEXT: 201011: 64 8b 00 movl %fs:(%rax), %eax
+//DISASM-NEXT: 201014: 48 8b 05 9d 10 00 00 movq 4253(%rip), %rax
+//DISASM-NEXT: 20101b: 64 8b 00 movl %fs:(%rax), %eax
+//DISASM-NEXT: 20101e: c3 retq
+
+.section .tdata,"awT",@progbits
+
+.text
+ .globl main
+ .align 16, 0x90
+ .type main,@function
+main:
+ movq tls1@GOTTPOFF(%rip), %rax
+ movl %fs:0(%rax), %eax
+ movq tls0@GOTTPOFF(%rip), %rax
+ movl %fs:0(%rax), %eax
+ movq tls0@GOTTPOFF(%rip), %rax
+ movl %fs:0(%rax), %eax
+ ret
diff --git a/test/ELF/tls-i686.s b/test/ELF/tls-i686.s
new file mode 100644 (file)
index 0000000..7f2dd60
--- /dev/null
@@ -0,0 +1,69 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: ld.lld %t -shared -o %tsharedout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+// RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC
+// RUN: llvm-objdump -d %tsharedout | FileCheck %s --check-prefix=DISSHARED
+// RUN: llvm-readobj -r %tsharedout | FileCheck %s --check-prefix=RELOCSHARED
+
+.section ".tdata", "awT", @progbits
+.globl var
+.globl var1
+var:
+.long 0
+var1:
+.long 1
+
+.section test, "awx"
+.global _start
+_start:
+ movl $var@tpoff, %edx
+ movl %gs:0, %ecx
+ subl %edx, %eax
+ movl $var1@tpoff, %edx
+ movl %gs:0, %ecx
+ subl %edx, %eax
+
+ movl %gs:0, %ecx
+ leal var@ntpoff(%ecx), %eax
+ movl %gs:0, %ecx
+ leal var1@ntpoff+123(%ecx), %eax
+
+// DIS:      Disassembly of section test:
+// DIS-NEXT: _start:
+// DIS-NEXT: 11000: ba 08 00 00 00       movl $8, %edx
+// DIS-NEXT: 11005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 1100c: 29 d0                subl %edx, %eax
+// DIS-NEXT: 1100e: ba 04 00 00 00       movl $4, %edx
+// DIS-NEXT: 11013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 1101a: 29 d0                subl %edx, %eax
+// DIS-NEXT: 1101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 11023: 8d 81 f8 ff ff ff    leal -8(%ecx), %eax
+// DIS-NEXT: 11029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 11030: 8d 81 77 00 00 00    leal 119(%ecx), %eax
+
+// RELOC: Relocations [
+// RELOC-NEXT: ]
+
+// DISSHARED: Disassembly of section test:
+// DISSHARED-NEXT: _start:
+// DISSHARED-NEXT: 1000: ba 00 00 00 00 movl   $0, %edx
+// DISSHARED-NEXT: 1005: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 100c: 29 d0 subl            %edx, %eax
+// DISSHARED-NEXT: 100e: ba 00 00 00 00        movl $0, %edx
+// DISSHARED-NEXT: 1013: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 101a: 29 d0 subl            %edx, %eax
+// DISSHARED-NEXT: 101c: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 1023: 8d 81 00 00 00 00     leal (%ecx), %eax
+// DISSHARED-NEXT: 1029: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx
+// DISSHARED-NEXT: 1030: 8d 81 7b 00 00 00     leal 123(%ecx), %eax
+
+// RELOCSHARED:      Relocations [
+// RELOCSHARED-NEXT: Section (4) .rel.dyn {
+// RELOCSHARED-NEXT:   0x1001 R_386_TLS_TPOFF32 var 0x0
+// RELOCSHARED-NEXT:   0x1025 R_386_TLS_TPOFF var 0x0
+// RELOCSHARED-NEXT:   0x100F R_386_TLS_TPOFF32 var1 0x0
+// RELOCSHARED-NEXT:   0x1032 R_386_TLS_TPOFF var1 0x0
+// RELOCSHARED-NEXT:  }
+// RELOCSHARED-NEXT: ]
diff --git a/test/ELF/tls-in-archive.s b/test/ELF/tls-in-archive.s
new file mode 100644 (file)
index 0000000..71f60e3
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-in-archive.s -o %t1.o
+// RUN: llvm-ar cru %t.a %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: ld.lld %t2.o %t.a -o %tout
+
+        .globl  _start
+_start:
+        movq    foo@gottpoff(%rip), %rax
+        .section        .tbss,"awT",@nobits
+        .weak   foo
diff --git a/test/ELF/tls-initial-exec-local.s b/test/ELF/tls-initial-exec-local.s
new file mode 100644 (file)
index 0000000..0aef3c8
--- /dev/null
@@ -0,0 +1,36 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t
+// RUN: llvm-readobj -r -s %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC (0x2)
+// CHECK-NEXT:   SHF_WRITE (0x1)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2090
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x2090 R_X86_64_TPOFF64 - 0x0
+// CHECK-NEXT:     0x2098 R_X86_64_TPOFF64 - 0x4
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// 0x1007 + 4233 = 0x2090
+// 0x100e + 4234 = 0x2098
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: .text:
+// DISASM-NEXT:  1000: {{.*}} addq      4233(%rip), %rax
+// DISASM-NEXT:  1007: {{.*}} addq      4234(%rip), %rax
+
+        addq    foo@GOTTPOFF(%rip), %rax
+        addq    bar@GOTTPOFF(%rip), %rax
+
+        .section        .tbss,"awT",@nobits
+foo:
+        .long 0
+bar:
+        .long 0
diff --git a/test/ELF/tls-mismatch.s b/test/ELF/tls-mismatch.s
new file mode 100644 (file)
index 0000000..21994d1
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-mismatch.s -o %t2
+// RUN: not ld.lld %t %t2 -o %t3 2>&1 | FileCheck %s
+
+// CHECK: TLS attribute mismatch: tlsvar
+// CHECK: >>> defined in
+// CHECK: >>> defined in
+
+.globl _start,tlsvar
+_start:
+  movl tlsvar,%edx
diff --git a/test/ELF/tls-offset.s b/test/ELF/tls-offset.s
new file mode 100644 (file)
index 0000000..75d9af7
--- /dev/null
@@ -0,0 +1,66 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -s %tout | FileCheck %s
+// RUN: echo "SECTIONS { \
+// RUN:   . = 0x201000; \
+// RUN:   .text : { *(.text) } \
+// RUN:   . = 0x202000; \
+// RUN:   .tdata : { *(.tdata) } \
+// RUN:   .tbss : { *(.tbss) } \
+// RUN:   .data.rel.ro : { *(.data.rel.ro) } \
+// RUN: }" > %t.script
+// RUN: ld.lld -T %t.script %t -o %tout2
+// RUN: echo SCRIPT
+// RUN: llvm-readobj -s %tout2 | FileCheck %s
+        .global _start
+_start:
+        retq
+
+        .section        .tdata,"awT",@progbits
+        .align  4
+        .long   42
+
+        .section        .tbss,"awT",@nobits
+        .align  16
+        .zero 16
+
+        .section        .data.rel.ro,"aw",@progbits
+        .long 1
+
+
+// Test that .tbss doesn't show up in the offset or in the address. If this
+// gets out of sync what we get a runtime is different from what the section
+// table says.
+
+// CHECK:      Name: .tdata
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_TLS
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x202000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 4
+
+// CHECK:      Name: .tbss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_TLS
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x202010
+// CHECK-NEXT: Offset: 0x2004
+// CHECK-NEXT: Size: 16
+
+// CHECK:      Name: .data.rel.ro
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x202004
+// CHECK-NEXT: Offset: 0x2004
+// CHECK-NEXT: Size: 4
diff --git a/test/ELF/tls-opt-gdie.s b/test/ELF/tls-opt-gdie.s
new file mode 100644 (file)
index 0000000..c423a3e
--- /dev/null
@@ -0,0 +1,52 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-opt-gdie.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t1
+// RUN: llvm-readobj -s -r %t1 | FileCheck --check-prefix=RELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+//RELOC:      Section {
+//RELOC:      Index:
+//RELOC:      Name: .got
+//RELOC-NEXT: Type: SHT_PROGBITS
+//RELOC-NEXT: Flags [
+//RELOC-NEXT:   SHF_ALLOC
+//RELOC-NEXT:   SHF_WRITE
+//RELOC-NEXT: ]
+//RELOC-NEXT: Address: 0x2020B0
+//RELOC-NEXT: Offset: 0x20B0
+//RELOC-NEXT: Size: 16
+//RELOC-NEXT: Link: 0
+//RELOC-NEXT: Info: 0
+//RELOC-NEXT: AddressAlignment: 8
+//RELOC-NEXT: EntrySize: 0
+//RELOC-NEXT: }
+//RELOC:      Relocations [
+//RELOC-NEXT:   Section (4) .rela.dyn {
+//RELOC-NEXT:     0x2020B0 R_X86_64_TPOFF64 tlsshared0 0x0
+//RELOC-NEXT:     0x2020B8 R_X86_64_TPOFF64 tlsshared1 0x0
+//RELOC-NEXT:   }
+//RELOC-NEXT: ]
+
+//0x201009 + (4256 + 7) = 0x2020B0
+//0x201019 + (4248 + 7) = 0x2020B8
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 201000: {{.*}} movq %fs:0, %rax
+// DISASM-NEXT: 201009: {{.*}} addq 4256(%rip), %rax
+// DISASM-NEXT: 201010: {{.*}} movq %fs:0, %rax
+// DISASM-NEXT: 201019: {{.*}} addq 4248(%rip), %rax
+
+.section .text
+.globl _start
+_start:
+ .byte 0x66
+ leaq tlsshared0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ .byte 0x66
+ leaq tlsshared1@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
diff --git a/test/ELF/tls-opt-gdiele-i686.s b/test/ELF/tls-opt-gdiele-i686.s
new file mode 100644 (file)
index 0000000..1432a96
--- /dev/null
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-gdiele-i686.s -o %tso.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld %t.o %tso -o %tout
+// RUN: llvm-readobj -r %tout | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: Section ({{.*}}) .rel.dyn {
+// NORELOC-NEXT:   0x12058 R_386_TLS_TPOFF tlsshared0 0x0
+// NORELOC-NEXT:   0x1205C R_386_TLS_TPOFF tlsshared1 0x0
+// NORELOC-NEXT:   }
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11006: 03 83 f8 ff ff ff addl -8(%ebx), %eax
+// DISASM-NEXT: 1100c: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11012: 03 83 fc ff ff ff addl -4(%ebx), %eax
+// DISASM-NEXT: 11018: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 1101e: 81 e8 08 00 00 00 subl $8, %eax
+// DISASM-NEXT: 11024: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 1102a: 81 e8 04 00 00 00 subl $4, %eax
+
+.type tlsexe1,@object
+.section .tbss,"awT",@nobits
+.globl tlsexe1
+.align 4
+tlsexe1:
+ .long 0
+ .size tlsexe1, 4
+
+.type tlsexe2,@object
+.section .tbss,"awT",@nobits
+.globl tlsexe2
+.align 4
+tlsexe2:
+ .long 0
+ .size tlsexe2, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section .text
+.globl _start
+_start:
+//GD->IE
+leal tlsshared0@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
+leal tlsshared1@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
+//GD->IE
+leal tlsexe1@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
+leal tlsexe2@tlsgd(,%ebx,1),%eax
+call ___tls_get_addr@plt
diff --git a/test/ELF/tls-opt-i686.s b/test/ELF/tls-opt-i686.s
new file mode 100644 (file)
index 0000000..dec45b4
--- /dev/null
@@ -0,0 +1,69 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// LD -> LE:
+// DISASM-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11006: 90                nop
+// DISASM-NEXT: 11007: 8d 74 26 00       leal (%esi), %esi
+// DISASM-NEXT: 1100b: 8d 90 f8 ff ff ff leal -8(%eax), %edx
+// DISASM-NEXT: 11011: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 11017: 90                nop
+// DISASM-NEXT: 11018: 8d 74 26 00       leal (%esi), %esi
+// DISASM-NEXT: 1101c: 8d 90 fc ff ff ff leal -4(%eax), %edx
+// IE -> LE:
+// 4294967288 == 0xFFFFFFF8
+// 4294967292 == 0xFFFFFFFC
+// DISASM-NEXT: 11022: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 11028: c7 c0 f8 ff ff ff  movl $4294967288, %eax
+// DISASM-NEXT: 1102e: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 11034: c7 c0 fc ff ff ff  movl $4294967292, %eax
+// DISASM-NEXT: 1103a: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 11040: 8d 80 f8 ff ff ff  leal -8(%eax), %eax
+// DISASM-NEXT: 11046: 65 a1 00 00 00 00  movl %gs:0, %eax
+// DISASM-NEXT: 1104c: 8d 80 fc ff ff ff  leal -4(%eax), %eax
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section .text
+.globl _start
+_start:
+//LD -> LE:
+leal tls0@tlsldm(%ebx),%eax
+call ___tls_get_addr@plt
+leal tls0@dtpoff(%eax),%edx
+leal tls1@tlsldm(%ebx),%eax
+call ___tls_get_addr@plt
+leal tls1@dtpoff(%eax),%edx
+//IE -> LE:
+movl %gs:0,%eax
+movl tls0@gotntpoff(%ebx),%eax
+movl %gs:0,%eax
+movl tls1@gotntpoff(%ebx),%eax
+movl %gs:0,%eax
+addl tls0@gotntpoff(%ebx),%eax
+movl %gs:0,%eax
+addl tls1@gotntpoff(%ebx),%eax
diff --git a/test/ELF/tls-opt-iele-i686-nopic.s b/test/ELF/tls-opt-iele-i686-nopic.s
new file mode 100644 (file)
index 0000000..b6608c1
--- /dev/null
@@ -0,0 +1,100 @@
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o
+// RUN: ld.lld -shared %tso.o -o %tso
+// RUN: ld.lld %t.o %tso -o %t1
+// RUN: llvm-readobj -s -r %t1 | FileCheck --check-prefix=GOTREL %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// GOTREL:      Section {
+// GOTREL:        Index:
+// GOTREL:        Name: .got
+// GOTREL-NEXT:   Type: SHT_PROGBITS
+// GOTREL-NEXT:   Flags [
+// GOTREL-NEXT:     SHF_ALLOC
+// GOTREL-NEXT:     SHF_WRITE
+// GOTREL-NEXT:   ]
+// GOTREL-NEXT:   Address: 0x12058
+// GOTREL-NEXT:   Offset: 0x2058
+// GOTREL-NEXT:   Size: 8
+// GOTREL-NEXT:   Link: 0
+// GOTREL-NEXT:   Info: 0
+// GOTREL-NEXT:   AddressAlignment: 4
+// GOTREL-NEXT:   EntrySize: 0
+// GOTREL-NEXT: }
+// GOTREL:      Relocations [
+// GOTREL-NEXT: Section ({{.*}}) .rel.dyn {
+// GOTREL-NEXT:   0x12058 R_386_TLS_TPOFF tlsshared0 0x0
+// GOTREL-NEXT:   0x1205C R_386_TLS_TPOFF tlsshared1 0x0
+// GOTREL-NEXT:  }
+// GOTREL-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// 4294967288 = 0xFFFFFFF8
+// 4294967292 = 0xFFFFFFFC
+// 73808 = (.got)[0] = 0x12058
+// 73812 = (.got)[1] = 0x1205C
+// DISASM-NEXT: 11000: c7 c1 f8 ff ff ff movl $4294967288, %ecx
+// DISASM-NEXT: 11006: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11009: b8 f8 ff ff ff    movl $4294967288, %eax
+// DISASM-NEXT: 1100e: 65 8b 00          movl %gs:(%eax), %eax
+// DISASM-NEXT: 11011: 81 c1 f8 ff ff ff addl $4294967288, %ecx
+// DISASM-NEXT: 11017: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 1101a: c7 c1 fc ff ff ff movl $4294967292, %ecx
+// DISASM-NEXT: 11020: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11023: b8 fc ff ff ff    movl $4294967292, %eax
+// DISASM-NEXT: 11028: 65 8b 00          movl %gs:(%eax), %eax
+// DISASM-NEXT: 1102b: 81 c1 fc ff ff ff addl $4294967292, %ecx
+// DISASM-NEXT: 11031: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11034: 8b 0d 58 20 01 00 movl 73816, %ecx
+// DISASM-NEXT: 1103a: 65 8b 01          movl %gs:(%ecx), %eax
+// DISASM-NEXT: 1103d: 03 0d 5c 20 01 00 addl 73820, %ecx
+// DISASM-NEXT: 11043: 65 8b 01          movl %gs:(%ecx), %eax
+
+.type tlslocal0,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal0
+.align 4
+tlslocal0:
+ .long 0
+ .size tlslocal0, 4
+
+.type tlslocal1,@object
+.section .tbss,"awT",@nobits
+.globl tlslocal1
+.align 4
+tlslocal1:
+ .long 0
+ .size tlslocal1, 4
+
+.section .text
+.globl ___tls_get_addr
+.type ___tls_get_addr,@function
+___tls_get_addr:
+
+.section .text
+.globl _start
+_start:
+movl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal0@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlslocal1@indntpoff,%eax
+movl %gs:(%eax),%eax
+
+addl tlslocal1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+movl tlsshared0@indntpoff,%ecx
+movl %gs:(%ecx),%eax
+
+addl tlsshared1@indntpoff,%ecx
+movl %gs:(%ecx),%eax
diff --git a/test/ELF/tls-opt-local.s b/test/ELF/tls-opt-local.s
new file mode 100644 (file)
index 0000000..633c22b
--- /dev/null
@@ -0,0 +1,52 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT: 201000: 48 c7 c0 f8 ff ff ff movq $-8, %rax
+// DISASM-NEXT: 201007: 49 c7 c7 f8 ff ff ff movq $-8, %r15
+// DISASM-NEXT: 20100e: 48 8d 80 f8 ff ff ff leaq -8(%rax), %rax
+// DISASM-NEXT: 201015: 4d 8d bf f8 ff ff ff leaq -8(%r15), %r15
+// DISASM-NEXT: 20101c: 48 81 c4 f8 ff ff ff addq $-8, %rsp
+// DISASM-NEXT: 201023: 49 81 c4 f8 ff ff ff addq $-8, %r12
+// DISASM-NEXT: 20102a: 48 c7 c0 fc ff ff ff movq $-4, %rax
+// DISASM-NEXT: 201031: 49 c7 c7 fc ff ff ff movq $-4, %r15
+// DISASM-NEXT: 201038: 48 8d 80 fc ff ff ff leaq -4(%rax), %rax
+// DISASM-NEXT: 20103f: 4d 8d bf fc ff ff ff leaq -4(%r15), %r15
+// DISASM-NEXT: 201046: 48 81 c4 fc ff ff ff addq $-4, %rsp
+// DISASM-NEXT: 20104d: 49 81 c4 fc ff ff ff addq $-4, %r12
+
+.section .tbss,"awT",@nobits
+
+.type tls0,@object
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.section .text
+.globl _start
+_start:
+ movq tls0@GOTTPOFF(%rip), %rax
+ movq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rax
+ addq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rsp
+ addq tls0@GOTTPOFF(%rip), %r12
+ movq tls1@GOTTPOFF(%rip), %rax
+ movq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rax
+ addq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rsp
+ addq tls1@GOTTPOFF(%rip), %r12
diff --git a/test/ELF/tls-opt-no-plt.s b/test/ELF/tls-opt-no-plt.s
new file mode 100644 (file)
index 0000000..53655d0
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-opt-gdie.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -s %t.exe | FileCheck %s
+
+// CHECK-NOT: .plt
+
+        .global _start
+_start:
+        data16
+        leaq    foo@TLSGD(%rip), %rdi
+        data16
+        data16
+        rex64
+        callq   __tls_get_addr@PLT
+
+        leaq    bar@TLSLD(%rip), %rdi
+        callq   __tls_get_addr@PLT
+        leaq    bar@DTPOFF(%rax), %rax
+
+        .type   bar,@object
+        .section        .tdata,"awT",@progbits
+        .align  8
+bar:
+        .long   42
+
+
+        .type   foo,@object
+        .section        .tdata,"awT",@progbits
+        .globl  foo
+        .align  8
+foo:
+        .long   42
diff --git a/test/ELF/tls-opt.s b/test/ELF/tls-opt.s
new file mode 100644 (file)
index 0000000..6835e06
--- /dev/null
@@ -0,0 +1,99 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s
+// RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s
+
+// NORELOC:      Relocations [
+// NORELOC-NEXT: ]
+
+// DISASM:      _start:
+// DISASM-NEXT: 201000: 48 c7 c0 f8 ff ff ff  movq $-8, %rax
+// DISASM-NEXT: 201007: 49 c7 c7 f8 ff ff ff  movq $-8, %r15
+// DISASM-NEXT: 20100e: 48 8d 80 f8 ff ff ff  leaq -8(%rax), %rax
+// DISASM-NEXT: 201015: 4d 8d bf f8 ff ff ff  leaq -8(%r15), %r15
+// DISASM-NEXT: 20101c: 48 81 c4 f8 ff ff ff  addq $-8, %rsp
+// DISASM-NEXT: 201023: 49 81 c4 f8 ff ff ff  addq $-8, %r12
+// DISASM-NEXT: 20102a: 48 c7 c0 fc ff ff ff  movq $-4, %rax
+// DISASM-NEXT: 201031: 49 c7 c7 fc ff ff ff  movq $-4, %r15
+// DISASM-NEXT: 201038: 48 8d 80 fc ff ff ff  leaq -4(%rax), %rax
+// DISASM-NEXT: 20103f: 4d 8d bf fc ff ff ff  leaq -4(%r15), %r15
+// DISASM-NEXT: 201046: 48 81 c4 fc ff ff ff  addq $-4, %rsp
+// DISASM-NEXT: 20104d: 49 81 c4 fc ff ff ff  addq $-4, %r12
+
+// LD to LE:
+// DISASM-NEXT: 201054: 66 66 66 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 201060: 48 8d 88 f8 ff ff ff                 leaq -8(%rax), %rcx
+// DISASM-NEXT: 201067: 66 66 66 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 201073: 48 8d 88 fc ff ff ff                 leaq -4(%rax), %rcx
+
+// GD to LE:
+// DISASM-NEXT: 20107a: 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 201083: 48 8d 80 f8 ff ff ff        leaq -8(%rax), %rax
+// DISASM-NEXT: 20108a: 64 48 8b 04 25 00 00 00 00  movq %fs:0, %rax
+// DISASM-NEXT: 201093: 48 8d 80 fc ff ff ff        leaq -4(%rax), %rax
+
+// LD to LE:
+// DISASM:     _DTPOFF64_1:
+// DISASM-NEXT: 20109a: f8 clc
+// DISASM:      _DTPOFF64_2:
+// DISASM-NEXT: 2010a3: fc cld
+
+.type tls0,@object
+.section .tbss,"awT",@nobits
+.globl tls0
+.align 4
+tls0:
+ .long 0
+ .size tls0, 4
+
+.type  tls1,@object
+.globl tls1
+.align 4
+tls1:
+ .long 0
+ .size tls1, 4
+
+.section .text
+.globl _start
+_start:
+ movq tls0@GOTTPOFF(%rip), %rax
+ movq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rax
+ addq tls0@GOTTPOFF(%rip), %r15
+ addq tls0@GOTTPOFF(%rip), %rsp
+ addq tls0@GOTTPOFF(%rip), %r12
+ movq tls1@GOTTPOFF(%rip), %rax
+ movq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rax
+ addq tls1@GOTTPOFF(%rip), %r15
+ addq tls1@GOTTPOFF(%rip), %rsp
+ addq tls1@GOTTPOFF(%rip), %r12
+
+ // LD to LE
+ leaq tls0@tlsld(%rip), %rdi
+ callq __tls_get_addr@PLT
+ leaq tls0@dtpoff(%rax),%rcx
+ leaq tls1@tlsld(%rip), %rdi
+ callq __tls_get_addr@PLT
+ leaq tls1@dtpoff(%rax),%rcx
+
+ // GD to LE
+ .byte 0x66
+ leaq tls0@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ .byte 0x66
+ leaq tls1@tlsgd(%rip),%rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+
+ // LD to LE
+_DTPOFF64_1:
+ .quad tls0@DTPOFF
+ nop
+
+_DTPOFF64_2:
+ .quad tls1@DTPOFF
+ nop
diff --git a/test/ELF/tls-relocatable.s b/test/ELF/tls-relocatable.s
new file mode 100644 (file)
index 0000000..2743861
--- /dev/null
@@ -0,0 +1,21 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -r -o %tr.o
+// RUN: ld.lld %tr.o -shared -o %t1
+// RUN: llvm-readobj -t %t1 | FileCheck %s
+
+// CHECK:       Symbol {
+// CHECK:         Name: tls0
+// CHECK-NEXT:    Value: 0x0
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Binding: Global
+// CHECK-NEXT:    Type: TLS
+// CHECK-NEXT:    Other: 0
+// CHECK-NEXT:    Section: .tdata
+// CHECK-NEXT:  }
+
+.type tls0,@object
+.section .tdata,"awT",@progbits
+.globl tls0
+tls0:
+ .long 0
diff --git a/test/ELF/tls-static.s b/test/ELF/tls-static.s
new file mode 100644 (file)
index 0000000..81ecc82
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared.s -o %tso
+// RUN: ld.lld -static %t -o %tout
+// RUN: ld.lld %t -o %tout
+// RUN: ld.lld -shared %tso -o %tshared
+// RUN: not ld.lld -static %t %tshared -o %tout 2>&1 | FileCheck %s
+// REQUIRES: x86
+
+.global _start
+_start:
+  call __tls_get_addr
+
+// CHECK: error: undefined symbol: __tls_get_addr
+// CHECK: >>> referenced by {{.*}}:(.text+0x1)
diff --git a/test/ELF/tls-two-relocs.s b/test/ELF/tls-two-relocs.s
new file mode 100644 (file)
index 0000000..7c5d6ab
--- /dev/null
@@ -0,0 +1,30 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout -shared
+// RUN: llvm-readobj -r %tout | FileCheck %s
+
+ data16
+ leaq   g_tls_s@TLSGD(%rip), %rdi
+ data16
+ data16
+ rex64
+ callq  __tls_get_addr@PLT
+
+ data16
+ leaq   g_tls_s@TLSGD(%rip), %rdi
+ data16
+ data16
+ rex64
+ callq  __tls_get_addr@PLT
+
+// Check that we handle two gd relocations to the same symbol.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (4) .rela.dyn {
+// CHECK-NEXT:     R_X86_64_DTPMOD64 g_tls_s 0x0
+// CHECK-NEXT:     R_X86_64_DTPOFF64 g_tls_s 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section (5) .rela.plt {
+// CHECK-NEXT:      R_X86_64_JUMP_SLOT __tls_get_addr 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/test/ELF/tls-weak-undef.s b/test/ELF/tls-weak-undef.s
new file mode 100644 (file)
index 0000000..7aa6ef1
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t --gc-sections
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
+// RUN:   %p/Inputs/tls-in-archive.s -o %t1.o
+// RUN: llvm-ar cru %t.a %t1.o
+// RUN: ld.lld %t.o %t.a -o %t
+
+// Check that lld doesn't crash because we don't reference
+// the TLS phdr when it's not created.
+        .globl  _start
+_start:
+        movq    foo@gottpoff(%rip), %rax
+        .section        .tbss,"awT",@nobits
+        .weak   foo
diff --git a/test/ELF/tls.s b/test/ELF/tls.s
new file mode 100644 (file)
index 0000000..a5b9559
--- /dev/null
@@ -0,0 +1,170 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld %t -o %tout
+// RUN: llvm-readobj -symbols -sections -program-headers %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+.global _start
+_start:
+  movl %fs:a@tpoff, %eax
+  movl %fs:b@tpoff, %eax
+  movl %fs:c@tpoff, %eax
+  movl %fs:d@tpoff, %eax
+
+  .global a
+       .section        .tbss,"awT",@nobits
+a:
+       .long   0
+
+  .global b
+       .section        .tdata,"awT",@progbits
+b:
+       .long   1
+
+  .global c
+       .section        .thread_bss,"awT",@nobits
+c:
+       .long   0
+
+  .global d
+       .section        .thread_data,"awT",@progbits
+d:
+       .long   2
+
+// CHECK:          Name: .tdata
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: [[TDATA_ADDR:0x.*]]
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .thread_data
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address:
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .tbss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: [[TBSS_ADDR:0x.*]]
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .thread_bss
+// CHECK-NEXT:     Type: SHT_NOBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_TLS
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+
+// 0x20200C = TBSS_ADDR + 4
+
+// CHECK-NEXT:     Address: 0x20200C
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 4
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment:
+// CHECK-NEXT:     EntrySize:
+// CHECK-NEXT:   }
+
+// CHECK:      Symbols [
+// CHECK:          Name: a
+// CHECK-NEXT:     Value: 0x8
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .tbss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: b
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .tdata
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: c
+// CHECK-NEXT:     Value: 0xC
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .thread_bss
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: d
+// CHECK-NEXT:     Value: 0x4
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: TLS
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .thread_data
+// CHECK-NEXT:   }
+
+// Check that the TLS NOBITS sections weren't added to the R/W PT_LOAD's size.
+
+// CHECK:      ProgramHeaders [
+// CHECK:          Type: PT_LOAD
+// CHECK:          Type: PT_LOAD
+// CHECK:          Type: PT_LOAD
+// CHECK:          FileSize: 8
+// CHECK-NEXT:     MemSize: 8
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       PF_R
+// CHECK-NEXT:       PF_W
+// CHECK-NEXT:     ]
+// CHECK:          Type: PT_TLS
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     VirtualAddress: [[TDATA_ADDR]]
+// CHECK-NEXT:     PhysicalAddress: [[TDATA_ADDR]]
+// CHECK-NEXT:     FileSize: 8
+// CHECK-NEXT:     MemSize: 16
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       PF_R
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Alignment:
+// CHECK-NEXT:   }
+
+// DIS:      Disassembly of section .text:
+// DIS-NEXT: _start:
+// DIS-NEXT:    201000: {{.+}} movl    %fs:-8, %eax
+// DIS-NEXT:    201008: {{.+}} movl    %fs:-16, %eax
+// DIS-NEXT:    201010: {{.+}} movl    %fs:-4, %eax
+// DIS-NEXT:    201018: {{.+}} movl    %fs:-12, %eax
diff --git a/test/ELF/trace-ar.s b/test/ELF/trace-ar.s
new file mode 100644 (file)
index 0000000..1d178dc
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.foo.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/trace-ar1.s -o %t.obj1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/trace-ar2.s -o %t.obj2.o
+# RUN: llvm-ar rcs %t.boo.a %t.obj1.o %t.obj2.o
+
+## Check how -t works with achieves
+# RUN: ld.lld %t.foo.o %t.boo.a -o %t.out -t 2>&1 | FileCheck %s
+# CHECK:      {{.*}}.foo.o
+# CHECK-NEXT: {{.*}}.boo.a({{.*}}.obj1.o)
+# CHECK-NOT:  {{.*}}.boo.a({{.*}}.obj2.o)
+
+## Test output with --start-lib
+# RUN: ld.lld %t.foo.o --start-lib %t.obj1.o %t.obj2.o -o %t.out -t 2>&1 | FileCheck --check-prefix=STARTLIB %s
+# STARTLIB:      {{.*}}.foo.o
+# STARTLIB-NEXT: {{.*}}.obj1.o
+# STARTLIB-NOT:  {{.*}}.obj2.o
+
+.globl _start, _used
+_start:
+ call _used
diff --git a/test/ELF/trace-symbols.s b/test/ELF/trace-symbols.s
new file mode 100644 (file)
index 0000000..eb8e17c
--- /dev/null
@@ -0,0 +1,78 @@
+# Test -y symbol and -trace-symbol=symbol
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/trace-symbols-foo-weak.s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/trace-symbols-foo-strong.s -o %t2
+# RUN: ld.lld -shared %t1 -o %t1.so
+# RUN: ld.lld -shared %t2 -o %t2.so
+# RUN: llvm-ar rcs %t1.a %t1
+# RUN: llvm-ar rcs %t2.a %t2
+
+# RUN: ld.lld -y foo -trace-symbol common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTRFOO %s
+# OBJECTRFOO: trace-symbols.s.tmp: reference to foo
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTDCOMMON %s
+# OBJECTDCOMMON: trace-symbols.s.tmp1: common definition of common
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD1FOO %s
+# OBJECTD1FOO: trace-symbols.s.tmp: reference to foo
+# OBJECTD1FOO: trace-symbols.s.tmp1: common definition of common
+# OBJECTD1FOO: trace-symbols.s.tmp1: definition of foo
+# OBJECTD1FOO: trace-symbols.s.tmp2: definition of foo
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN:   %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common --trace-symbol=hsymbol \
+# RUN:   %t %t2 %t1 -o %t4 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=OBJECTD2FOO %s
+# OBJECTD2FOO: trace-symbols.s.tmp2: definition of foo
+
+# RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=SHLIBDCOMMON %s
+# SHLIBDCOMMON: trace-symbols.s.tmp1.so: definition of common
+
+# RUN: ld.lld -y foo -y common %t %t2.so %t1.so -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=SHLIBD2FOO %s
+# RUN: ld.lld -y foo %t %t1.a %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=NO-SHLIBD2FOO %s
+# SHLIBD2FOO:        trace-symbols.s.tmp2.so: definition of foo
+# NO-SHLIBD2FOO-NOT: trace-symbols.s.tmp2.so: definition of foo
+
+# RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \
+# RUN:   FileCheck -check-prefix=ARCHIVEDCOMMON %s
+# ARCHIVEDCOMMON-NOT: trace-symbols.s.tmp1.a(trace-symbols.s.tmp1): definition of \
+# common
+
+# RUN: ld.lld -y foo %t %t1.a %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=ARCHIVED1FOO %s
+# ARCHIVED1FOO: trace-symbols.s.tmp1.a(trace-symbols.s.tmp1): definition of foo
+
+# RUN: ld.lld -y foo %t %t1.a %t2.a -o %t3 | \
+# RUN:   FileCheck -check-prefix=ARCHIVED2FOO %s
+# ARCHIVED2FOO: trace-symbols.s.tmp2.a(trace-symbols.s.tmp2): definition of foo
+
+# RUN: ld.lld -y bar %t %t1.so %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=SHLIBDBAR %s
+# SHLIBDBAR: trace-symbols.s.tmp2.so: definition of bar
+
+# RUN: ld.lld -y foo -y bar %t %t1.so %t2.so -o %t3 | \
+# RUN:   FileCheck -check-prefix=SHLIBRBAR %s
+# SHLIBRBAR-NOT: trace-symbols.s.tmp1.so: reference to bar
+
+# RUN: ld.lld -y foo -y bar %t -u bar --start-lib %t1 %t2 --end-lib -o %t3 | \
+# RUN:   FileCheck -check-prefix=STARTLIB %s
+# STARTLIB: trace-symbols.s.tmp1: reference to bar
+
+.hidden hsymbol
+.globl _start
+.type  _start, @function
+_start:
+call foo
diff --git a/test/ELF/trace.s b/test/ELF/trace.s
new file mode 100644 (file)
index 0000000..4374d93
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.foo.o
+
+## Check -t
+# RUN: ld.lld -shared %t.foo.o -o %t.so -t 2>&1 | FileCheck %s
+# CHECK: {{.*}}.foo.o
+
+## Check --trace alias
+# RUN: ld.lld -shared %t.foo.o -o %t.so -t 2>&1 | FileCheck %s
diff --git a/test/ELF/ttext-tdata-tbss.s b/test/ELF/ttext-tdata-tbss.s
new file mode 100644 (file)
index 0000000..a52d88b
--- /dev/null
@@ -0,0 +1,66 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+## Show what regular output gives to us.
+# RUN: ld.lld %t.o -o %t1
+# RUN: llvm-readobj --elf-output-style=GNU -l -s  %t1 | FileCheck %s
+# CHECK:      .rodata   PROGBITS 0000000000200158 000158 000008
+# CHECK-NEXT: .text     PROGBITS 0000000000201000 001000 000001
+# CHECK-NEXT: .aw       PROGBITS 0000000000202000 002000 000008
+# CHECK-NEXT: .data     PROGBITS 0000000000202008 002008 000008
+# CHECK-NEXT: .bss      NOBITS   0000000000202010 002010 000008
+# CHECK:      Type
+# CHECK-NEXT: PHDR
+# CHECK-NEXT: LOAD 0x000000 0x0000000000200000
+
+## With .text at 0 there is no space to allocate the headers.
+# RUN: ld.lld -Ttext 0x0 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t2
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck %s --check-prefix=USER1
+# USER1:      .text   PROGBITS 0000000000000000 001000 000001
+# USER1-NEXT: .data   PROGBITS 0000000000004000 002000 000008
+# USER1-NEXT: .bss    NOBITS   0000000000008000 002008 000008
+# USER1-NEXT: .rodata PROGBITS 0000000000009000 003000 000008
+# USER1-NEXT: .aw     PROGBITS 000000000000a000 004000 000008
+# USER1:      Type
+# USER1-NEXT: LOAD 0x001000 0x0000000000000000
+
+## With .text at 0x1000 there is space to allocate the headers.
+# RUN: ld.lld -Ttext 0x1000 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t3
+# RUN: llvm-readobj --elf-output-style=GNU -l -s  %t3 | FileCheck %s --check-prefix=USER2
+# USER2:      .text   PROGBITS 0000000000001000 001000 000001
+# USER2-NEXT: .data   PROGBITS 0000000000004000 002000 000008
+# USER2-NEXT: .bss    NOBITS   0000000000008000 002008 000008
+# USER2-NEXT: .rodata PROGBITS 0000000000009000 003000 000008
+# USER2-NEXT: .aw     PROGBITS 000000000000a000 004000 000008
+# USER2:      Type
+# USER2-NEXT: PHDR
+# USER2-NEXT: LOAD 0x000000 0x0000000000000000
+
+## With .text well above 200000 we don't need to change the image base
+# RUN: ld.lld -Ttext 0x201000 %t.o -o %t4
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t4 | FileCheck %s --check-prefix=USER3
+# USER3:     .text   PROGBITS 0000000000201000 001000 000001
+# USER3-NEX: .rodata PROGBITS 0000000000202000 002000 000008
+# USER3-NEX: .aw     PROGBITS 0000000000203000 003000 000008
+# USER3-NEX: .data   PROGBITS 0000000000203008 003008 000008
+# USER3-NEX: .bss    NOBITS   0000000000203010 003010 000008
+# USER3:      Type
+# USER3-NEXT: PHDR
+# USER3-NEXT: LOAD 0x000000 0x0000000000200000
+
+.text
+.globl _start
+_start:
+ nop
+
+.section .rodata,"a"
+ .quad 0
+
+.section .aw,"aw"
+ .quad 0
+
+.section .data,"aw"
+ .quad 0
+
+.section .bss,"",@nobits
+ .quad 0
diff --git a/test/ELF/undef-shared.s b/test/ELF/undef-shared.s
new file mode 100644 (file)
index 0000000..bc38b60
--- /dev/null
@@ -0,0 +1,22 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: hidden
+# CHECK: >>> referenced by {{.*}}:(.data+0x0)
+.global hidden
+.hidden hidden
+
+# CHECK: error: undefined symbol: internal
+# CHECK: >>> referenced by {{.*}}:(.data+0x8)
+.global internal
+.internal internal
+
+# CHECK: error: undefined symbol: protected
+# CHECK: >>> referenced by {{.*}}:(.data+0x10)
+.global protected
+.protected protected
+
+.section .data, "a"
+ .quad hidden
+ .quad internal
+ .quad protected
diff --git a/test/ELF/undef-start.s b/test/ELF/undef-start.s
new file mode 100644 (file)
index 0000000..590d0a8
--- /dev/null
@@ -0,0 +1,3 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld %t -o %t2 2>&1
+# REQUIRES: x86
diff --git a/test/ELF/undef-version-script.s b/test/ELF/undef-version-script.s
new file mode 100644 (file)
index 0000000..5297283
--- /dev/null
@@ -0,0 +1,40 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "{ local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# This does not match gold's behavior because gold does not create undefined
+# symbols in dynsym without an appropriate (e.g. PLT) relocation in the input.
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: bar@
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Weak (0x2)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo@
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global foo
+.weak bar
diff --git a/test/ELF/undef-with-plt-addr-i686.s b/test/ELF/undef-with-plt-addr-i686.s
new file mode 100644 (file)
index 0000000..755f0da
--- /dev/null
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -t -s %t3 | FileCheck %s
+
+.globl _start
+_start:
+mov $set_data, %eax
+
+// Test that set_data has an address in the .plt
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11010
+
+// CHECK:      Name:    set_data
+// CHECK-NEXT: Value:   0x11020
diff --git a/test/ELF/undef-with-plt-addr.s b/test/ELF/undef-with-plt-addr.s
new file mode 100644 (file)
index 0000000..d34859c
--- /dev/null
@@ -0,0 +1,48 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -t -s -r %t3 | FileCheck %s
+
+// Test that -z nocopyreloc doesn't prevent the plt hack.
+// RUN: ld.lld %t.o %t2.so -o %t3 -z nocopyreloc
+
+.globl _start
+_start:
+movabsq        $set_data, %rax
+
+.data
+.quad foo
+// Test that set_data has an address in the .plt, but foo is not
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x201010
+
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   0x202000 R_X86_64_64 foo 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:   0x202020 R_X86_64_JUMP_SLOT set_data 0x0
+// CHECK-NEXT: }
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+// CHECK:      Name:    set_data
+// CHECK-NEXT: Value:   0x201020
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
diff --git a/test/ELF/undef.s b/test/ELF/undef.s
new file mode 100644 (file)
index 0000000..49f8410
--- /dev/null
@@ -0,0 +1,47 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-debug.s -o %t3.o
+# RUN: llvm-ar rc %t2.a %t2.o
+# RUN: not ld.lld %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s
+# RUN: not ld.lld -pie %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: foo
+# CHECK: >>> referenced by undef.s
+# CHECK:                   {{.*}}:(.text+0x1)
+
+# CHECK: error: undefined symbol: bar
+# CHECK: >>> referenced by undef.s
+# CHECK: >>>               {{.*}}:(.text+0x6)
+
+# CHECK: error: undefined symbol: foo(int)
+# CHECK: >>> referenced by undef.s
+# CHECK: >>>               {{.*}}:(.text+0x10)
+
+# CHECK: error: undefined symbol: zed2
+# CHECK: >>> referenced by {{.*}}.o:(.text+0x0) in archive {{.*}}2.a
+
+# CHECK: error: undefined symbol: zed3
+# CHECK: >>> referenced by undef-debug.s:3 (dir{{/|\\}}undef-debug.s:3)
+# CHECK: >>>               {{.*}}.o:(.text+0x0)
+
+# CHECK: error: undefined symbol: zed4
+# CHECK: >>> referenced by undef-debug.s:7 (dir{{/|\\}}undef-debug.s:7)
+# CHECK: >>>               {{.*}}.o:(.text.1+0x0)
+
+# CHECK: error: undefined symbol: zed5
+# CHECK: >>> referenced by undef-debug.s:11 (dir{{/|\\}}undef-debug.s:11)
+# CHECK: >>>               {{.*}}.o:(.text.2+0x0)
+
+# RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \
+# RUN:   FileCheck -check-prefix=NO-DEMANGLE %s
+# NO-DEMANGLE: error: undefined symbol: _Z3fooi
+
+.file "undef.s"
+
+  .globl _start
+_start:
+  call foo
+  call bar
+  call zed1
+  call _Z3fooi
diff --git a/test/ELF/undefined-opt.s b/test/ELF/undefined-opt.s
new file mode 100644 (file)
index 0000000..d8b793d
--- /dev/null
@@ -0,0 +1,68 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:     %p/Inputs/abs.s -o %tabs.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN:     %p/Inputs/shared.s -o %tshared.o
+# RUN: rm -f %tar.a
+# RUN: llvm-ar rcs %tar.a %tabs.o %tshared.o
+# REQUIRES: x86
+
+# Symbols from the archive are not in if not needed
+# RUN: ld.lld -o %t1 %t.o %tar.a
+# RUN: llvm-readobj --symbols %t1 | FileCheck --check-prefix=NO-UNDEFINED %s
+# NO-UNDEFINED: Symbols [
+# NO-UNDEFINED-NOT: Name: abs
+# NO-UNDEFINED-NOT: Name: big
+# NO-UNDEFINED-NOT: Name: bar
+# NO-UNDEFINED-NOT: Name: zed
+# NO-UNDEFINED: ]
+
+# Symbols from the archive are in if needed, but only from the
+# containing object file
+# RUN: ld.lld -o %t2 %t.o %tar.a -u bar
+# RUN: llvm-readobj --symbols %t2 | FileCheck --check-prefix=ONE-UNDEFINED %s
+# ONE-UNDEFINED: Symbols [
+# ONE-UNDEFINED-NOT: Name: abs
+# ONE-UNDEFINED-NOT: Name: big
+# ONE-UNDEFINED: Name: bar
+# ONE-UNDEFINED: Name: zed
+# ONE-UNDEFINED: ]
+
+# Use the option couple of times, both short and long forms
+# RUN: ld.lld -o %t3 %t.o %tar.a -u bar --undefined=abs
+# RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TWO-UNDEFINED %s
+# RUN: ld.lld -o %t3 %t.o %tar.a -u bar --undefined abs
+# RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TWO-UNDEFINED %s
+# TWO-UNDEFINED: Symbols [
+# TWO-UNDEFINED: Name: abs
+# TWO-UNDEFINED: Name: big
+# TWO-UNDEFINED: Name: bar
+# TWO-UNDEFINED: Name: zed
+# TWO-UNDEFINED: ]
+# Now the same logic but linker script is used to set undefines
+# RUN: echo "EXTERN( bar abs )" > %t.script
+# RUN: ld.lld -o %t3 %t.o %tar.a %t.script
+# RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TWO-UNDEFINED %s
+
+# Added undefined symbol may be left undefined without error, but
+# shouldn't show up in the dynamic table.
+# RUN: ld.lld -shared -o %t4 %t.o %tar.a -u unknown
+# RUN: llvm-readobj --dyn-symbols %t4 | \
+# RUN:     FileCheck --check-prefix=UNK-UNDEFINED-SO %s
+# UNK-UNDEFINED-SO: DynamicSymbols [
+# UNK-UNDEFINED-SO-NOT:     Name: unknown
+# UNK-UNDEFINED-SO: ]
+
+# Added undefined symbols should appear in the dynamic table if necessary.
+# RUN: ld.lld -shared -o %t5 %t.o -u export
+# RUN: llvm-readobj --dyn-symbols %t5 | \
+# RUN:     FileCheck --check-prefix=EXPORT-SO %s
+# EXPORT-SO: DynamicSymbols [
+# EXPORT-SO:   Name: export
+# EXPORT-SO: ]
+
+.globl _start
+_start:
+
+.globl export
+export:
diff --git a/test/ELF/undefined-versioned-symbol.s b/test/ELF/undefined-versioned-symbol.s
new file mode 100644 (file)
index 0000000..afa0ab9
--- /dev/null
@@ -0,0 +1,74 @@
+// REQUIRES: x86
+// RUN: echo ".data; \
+// RUN:       .quad \"basename\"; \
+// RUN:       .quad \"basename@FBSD_1.0\"; \
+// RUN:       .quad \"basename@FBSD_1.1\" " > %t.s
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t.s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: echo "FBSD_1.0 { local: *; }; FBSD_1.1 { };" > %t2.ver
+// RUN: ld.lld --shared --version-script %t2.ver %t2.o -o %t2.so
+// RUN: echo "LIBPKG_1.3 { };" > %t.ver
+// RUN: ld.lld --shared %t.o --version-script %t.ver %t2.so -o %t.so
+// RUN: llvm-readobj --dyn-symbols -r --expand-relocs %t.so | FileCheck %s
+
+// Test that each relocation points to the correct version.
+
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   Relocation {
+// CHECK-NEXT:     Offset: 0x1000
+// CHECK-NEXT:     Type: R_X86_64_64 (1)
+// CHECK-NEXT:     Symbol: basename (1)
+// CHECK-NEXT:     Addend: 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Relocation {
+// CHECK-NEXT:     Offset: 0x1008
+// CHECK-NEXT:     Type: R_X86_64_64 (1)
+// CHECK-NEXT:     Symbol: basename (2)
+// CHECK-NEXT:     Addend: 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Relocation {
+// CHECK-NEXT:     Offset: 0x1010
+// CHECK-NEXT:     Type: R_X86_64_64 (1)
+// CHECK-NEXT:     Symbol: basename (3)
+// CHECK-NEXT:     Addend: 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
+
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding:
+// CHECK-NEXT:     Type:
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: basename@FBSD_1.1
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding:
+// CHECK-NEXT:     Type:
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: basename@FBSD_1.0
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size:
+// CHECK-NEXT:     Binding:
+// CHECK-NEXT:     Type:
+// CHECK-NEXT:     Other:
+// CHECK-NEXT:     Section:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: basename@FBSD_1.1
+
+
+.global "basename@FBSD_1.0"
+"basename@FBSD_1.0":
+
+.global "basename@@FBSD_1.1"
+"basename@@FBSD_1.1":
diff --git a/test/ELF/unresolved-symbols.s b/test/ELF/unresolved-symbols.s
new file mode 100644 (file)
index 0000000..18656dc
--- /dev/null
@@ -0,0 +1,65 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/unresolved-symbols.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t.so
+
+## Check that %t2.o contains undefined symbol undef.
+# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | \
+# RUN:   FileCheck -check-prefix=UNDCHECK %s
+# UNDCHECK: error: undefined symbol: undef
+# UNDCHECK: >>> referenced by {{.*}}2.o:(.text+0x1)
+
+## Error out if unknown option value was set.
+# RUN: not ld.lld %t1.o %t2.o -o %t --unresolved-symbols=xxx 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR1 %s
+# ERR1: unknown --unresolved-symbols value: xxx
+
+## Ignore all should not produce error for symbols from object except
+## case when --no-undefined specified.
+# RUN: ld.lld %t2.o -o %t1_1 --unresolved-symbols=ignore-all
+# RUN: llvm-readobj %t1_1 > /dev/null 2>&1
+# RUN: not ld.lld %t2.o -o %t1_2 --unresolved-symbols=ignore-all --no-undefined 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERRUND %s
+# ERRUND: error: undefined symbol: undef
+# ERRUND: >>> referenced by {{.*}}:(.text+0x1)
+
+## Also ignore all should not produce error for symbols from DSOs.
+# RUN: ld.lld %t1.o %t.so -o %t1_3 --unresolved-symbols=ignore-all
+# RUN: llvm-readobj %t1_3 > /dev/null 2>&1
+
+## Ignoring undefines in objects should not produce error for symbol from object.
+# RUN: ld.lld %t1.o %t2.o -o %t2 --unresolved-symbols=ignore-in-object-files
+# RUN: llvm-readobj %t2 > /dev/null 2>&1
+## And still should not should produce for undefines from DSOs.
+# RUN: ld.lld %t1.o %t.so -o %t2_1 --unresolved-symbols=ignore-in-object-files
+# RUN: llvm-readobj %t2 > /dev/null 2>&1
+
+## Ignoring undefines in shared should produce error for symbol from object.
+# RUN: not ld.lld %t2.o -o %t3 --unresolved-symbols=ignore-in-shared-libs 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERRUND %s
+## And should not produce errors for symbols from DSO.
+# RUN: ld.lld %t1.o %t.so -o %t3_1 --unresolved-symbols=ignore-in-shared-libs
+# RUN: llvm-readobj %t3_1 > /dev/null 2>&1
+
+## Ignoring undefines in shared libs should not produce error for symbol from object
+## if we are linking DSO.
+# RUN: ld.lld -shared %t1.o -o %t4 --unresolved-symbols=ignore-in-shared-libs
+# RUN: llvm-readobj %t4 > /dev/null 2>&1
+
+## Do not report undefines if linking relocatable.
+# RUN: ld.lld -r %t1.o %t2.o -o %t5 --unresolved-symbols=report-all
+# RUN: llvm-readobj %t5 > /dev/null 2>&1
+
+## report-all is the default one. Check that we do not report
+## undefines from DSO and do report undefines from object. With
+## report-all specified and without.
+# RUN: ld.lld -shared %t1.o %t.so -o %t6 --unresolved-symbols=report-all
+# RUN: llvm-readobj %t6 > /dev/null 2>&1
+# RUN: ld.lld -shared %t1.o %t.so -o %t6_1
+# RUN: llvm-readobj %t6_1 > /dev/null 2>&1
+# RUN: not ld.lld %t2.o -o %t7 --unresolved-symbols=report-all 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERRUND %s
+# RUN: not ld.lld %t2.o -o %t7_1 2>&1 | FileCheck -check-prefix=ERRUND %s
+
+.globl _start
+_start:
diff --git a/test/ELF/user_def_init_array_start.s b/test/ELF/user_def_init_array_start.s
new file mode 100644 (file)
index 0000000..6c33166
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t2.so -shared
+// Allow user defined __init_array_start. This is used by musl because of the
+// the bfd linker not handling these properly. We always create them as
+// hidden, musl should not have problems with lld.
+
+        .hidden __init_array_start
+        .globl  __init_array_start
+__init_array_start:
+        .zero   8
diff --git a/test/ELF/verdef-defaultver.s b/test/ELF/verdef-defaultver.s
new file mode 100644 (file)
index 0000000..c37c90a
--- /dev/null
@@ -0,0 +1,201 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/verdef-defaultver.s -o %t1
+# RUN: echo "V1 { global: a; local: *; };" > %t.script
+# RUN: echo "V2 { global: b; c; } V1;" >> %t.script
+# RUN: ld.lld -shared -soname shared %t1 --version-script %t.script -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:      DynamicSymbols [
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: @
+# DSO-NEXT:      Value: 0x0
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Local
+# DSO-NEXT:      Type: None
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: Undefined
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: a@@V1
+# DSO-NEXT:      Value: 0x1000
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: b@@V2
+# DSO-NEXT:      Value: 0x1002
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: b@V1
+# DSO-NEXT:      Value: 0x1001
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: c@@V2
+# DSO-NEXT:      Value: 0x1003
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:  ]
+# DSO-NEXT:  Version symbols {
+# DSO-NEXT:    Section Name: .gnu.version
+# DSO-NEXT:    Address: 0x240
+# DSO-NEXT:    Offset: 0x240
+# DSO-NEXT:    Link: 1
+# DSO-NEXT:    Symbols [
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 0
+# DSO-NEXT:        Name: @
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: a@@V1
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 3
+# DSO-NEXT:        Name: b@@V2
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: b@V1
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 3
+# DSO-NEXT:        Name: c@@V2
+# DSO-NEXT:      }
+# DSO-NEXT:    ]
+# DSO-NEXT:  }
+# DSO-NEXT:  SHT_GNU_verdef {
+# DSO-NEXT:    Definition {
+# DSO-NEXT:      Version: 1
+# DSO-NEXT:      Flags: Base
+# DSO-NEXT:      Index: 1
+# DSO-NEXT:      Hash: 127830196
+# DSO-NEXT:      Name: shared
+# DSO-NEXT:    }
+# DSO-NEXT:    Definition {
+# DSO-NEXT:      Version: 1
+# DSO-NEXT:      Flags: 0x0
+# DSO-NEXT:      Index: 2
+# DSO-NEXT:      Hash: 1425
+# DSO-NEXT:      Name: V1
+# DSO-NEXT:    }
+# DSO-NEXT:    Definition {
+# DSO-NEXT:      Version: 1
+# DSO-NEXT:      Flags: 0x0
+# DSO-NEXT:      Index: 3
+# DSO-NEXT:      Hash: 1426
+# DSO-NEXT:      Name: V2
+# DSO-NEXT:    }
+# DSO-NEXT:  }
+
+## Check that we can link against DSO produced.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2
+# RUN: ld.lld %t2 %t.so -o %t3
+# RUN: llvm-readobj -V -dyn-symbols %t3 | FileCheck --check-prefix=EXE %s
+
+# EXE:      DynamicSymbols [
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: @
+# EXE-NEXT:      Value: 0x0
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Local
+# EXE-NEXT:      Type: None
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: a@V1
+# EXE-NEXT:      Value: 0x201020
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Global
+# EXE-NEXT:      Type: Function
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: b@V2
+# EXE-NEXT:      Value: 0x201030
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Global
+# EXE-NEXT:      Type: Function
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:    Symbol {
+# EXE-NEXT:      Name: c@V2
+# EXE-NEXT:      Value: 0x201040
+# EXE-NEXT:      Size: 0
+# EXE-NEXT:      Binding: Global
+# EXE-NEXT:      Type: Function
+# EXE-NEXT:      Other: 0
+# EXE-NEXT:      Section: Undefined
+# EXE-NEXT:    }
+# EXE-NEXT:  ]
+# EXE-NEXT:  Version symbols {
+# EXE-NEXT:    Section Name: .gnu.version
+# EXE-NEXT:    Address: 0x200228
+# EXE-NEXT:    Offset: 0x228
+# EXE-NEXT:    Link: 1
+# EXE-NEXT:    Symbols [
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 0
+# EXE-NEXT:        Name: @
+# EXE-NEXT:      }
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 2
+# EXE-NEXT:        Name: a@V1
+# EXE-NEXT:      }
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 3
+# EXE-NEXT:        Name: b@V2
+# EXE-NEXT:      }
+# EXE-NEXT:      Symbol {
+# EXE-NEXT:        Version: 3
+# EXE-NEXT:        Name: c@V2
+# EXE-NEXT:      }
+# EXE-NEXT:    ]
+# EXE-NEXT:  }
+# EXE-NEXT:  SHT_GNU_verdef {
+# EXE-NEXT:  }
+# EXE-NEXT:  SHT_GNU_verneed {
+# EXE-NEXT:    Dependency {
+# EXE-NEXT:      Version: 1
+# EXE-NEXT:      Count: 2
+# EXE-NEXT:      FileName: shared
+# EXE-NEXT:      Entry {
+# EXE-NEXT:        Hash: 1425
+# EXE-NEXT:        Flags: 0x0
+# EXE-NEXT:        Index: 2
+# EXE-NEXT:        Name: V1
+# EXE-NEXT:      }
+# EXE-NEXT:      Entry {
+# EXE-NEXT:        Hash: 1426
+# EXE-NEXT:        Flags: 0x0
+# EXE-NEXT:        Index: 3
+# EXE-NEXT:        Name: V2
+# EXE-NEXT:      }
+# EXE-NEXT:    }
+# EXE-NEXT:  }
+
+.globl _start
+_start:
+  callq a
+  callq b
+  callq c
diff --git a/test/ELF/verdef-dependency.s b/test/ELF/verdef-dependency.s
new file mode 100644 (file)
index 0000000..3f12685
--- /dev/null
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0 { global: a; local: *; };" > %t.script
+# RUN: echo "LIBSAMPLE_2.0 { global: b; local: *; } LIBSAMPLE_1.0;" >> %t.script
+# RUN: echo "LIBSAMPLE_3.0 { global: c; } LIBSAMPLE_2.0;" >> %t.script
+# RUN: ld.lld --version-script %t.script -shared -soname shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:      SHT_GNU_verdef {
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: Base
+# DSO-NEXT:     Index: 1
+# DSO-NEXT:     Hash: 127830196
+# DSO-NEXT:     Name: shared
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 2
+# DSO-NEXT:     Hash: 98457184
+# DSO-NEXT:     Name: LIBSAMPLE_1.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 3
+# DSO-NEXT:     Hash: 98456416
+# DSO-NEXT:     Name: LIBSAMPLE_2.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 4
+# DSO-NEXT:     Hash: 98456672
+# DSO-NEXT:     Name: LIBSAMPLE_3.0
+# DSO-NEXT:   }
+# DSO-NEXT: }
diff --git a/test/ELF/verdef.s b/test/ELF/verdef.s
new file mode 100644 (file)
index 0000000..7fd60a9
--- /dev/null
@@ -0,0 +1,119 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0 { global: a; local: *; };" > %t.script
+# RUN: echo "LIBSAMPLE_2.0 { global: b; local: *; };" >> %t.script
+# RUN: echo "LIBSAMPLE_3.0 { global: c; local: *; };" >> %t.script
+# RUN: ld.lld --version-script %t.script -shared -soname shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:        Version symbols {
+# DSO-NEXT:   Section Name: .gnu.version
+# DSO-NEXT:   Address: 0x228
+# DSO-NEXT:   Offset: 0x228
+# DSO-NEXT:   Link: 1
+# DSO-NEXT:   Symbols [
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 0
+# DSO-NEXT:       Name: @
+# DSO-NEXT:     }
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 2
+# DSO-NEXT:       Name: a@@LIBSAMPLE_1.0
+# DSO-NEXT:     }
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 3
+# DSO-NEXT:       Name: b@@LIBSAMPLE_2.0
+# DSO-NEXT:     }
+# DSO-NEXT:     Symbol {
+# DSO-NEXT:       Version: 4
+# DSO-NEXT:       Name: c@@LIBSAMPLE_3.0
+# DSO-NEXT:     }
+# DSO-NEXT:   ]
+# DSO-NEXT: }
+# DSO-NEXT: SHT_GNU_verdef {
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: Base
+# DSO-NEXT:     Index: 1
+# DSO-NEXT:     Hash: 127830196
+# DSO-NEXT:     Name: shared
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 2
+# DSO-NEXT:     Hash: 98457184
+# DSO-NEXT:     Name: LIBSAMPLE_1.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 3
+# DSO-NEXT:     Hash: 98456416
+# DSO-NEXT:     Name: LIBSAMPLE_2.0
+# DSO-NEXT:   }
+# DSO-NEXT:   Definition {
+# DSO-NEXT:     Version: 1
+# DSO-NEXT:     Flags: 0x0
+# DSO-NEXT:     Index: 4
+# DSO-NEXT:     Hash: 98456672
+# DSO-NEXT:     Name: LIBSAMPLE_3.0
+# DSO-NEXT:   }
+# DSO-NEXT: }
+# DSO-NEXT: SHT_GNU_verneed {
+# DSO-NEXT: }
+
+## Check that we can link agains DSO we produced.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/verdef.s -o %tmain.o
+# RUN: ld.lld %tmain.o %t.so -o %tout
+# RUN: llvm-readobj -V %tout | FileCheck --check-prefix=MAIN %s
+
+# MAIN:      Version symbols {
+# MAIN-NEXT:   Section Name: .gnu.version
+# MAIN-NEXT:   Address: 0x200228
+# MAIN-NEXT:   Offset: 0x228
+# MAIN-NEXT:   Link: 1
+# MAIN-NEXT:   Symbols [
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 0
+# MAIN-NEXT:       Name: @
+# MAIN-NEXT:     }
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 2
+# MAIN-NEXT:       Name: a@LIBSAMPLE_1.0
+# MAIN-NEXT:     }
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 3
+# MAIN-NEXT:       Name: b@LIBSAMPLE_2.0
+# MAIN-NEXT:     }
+# MAIN-NEXT:     Symbol {
+# MAIN-NEXT:       Version: 4
+# MAIN-NEXT:       Name: c@LIBSAMPLE_3.0
+# MAIN-NEXT:     }
+# MAIN-NEXT:   ]
+# MAIN-NEXT: }
+# MAIN-NEXT: SHT_GNU_verdef {
+# MAIN-NEXT: }
+
+# RUN: echo "VERSION {" > %t.script
+# RUN: echo "LIBSAMPLE_1.0 { global: a; local: *; };" >> %t.script
+# RUN: echo "LIBSAMPLE_2.0 { global: b; local: *; };" >> %t.script
+# RUN: echo "LIBSAMPLE_3.0 { global: c; local: *; };" >> %t.script
+# RUN: echo "}" >> %t.script
+# RUN: ld.lld --script %t.script -shared -soname shared %t.o -o %t2.so
+# RUN: llvm-readobj -V -dyn-symbols %t2.so | FileCheck --check-prefix=DSO %s
+
+.globl a
+.type  a,@function
+a:
+retq
+
+.globl b
+.type  b,@function
+b:
+retq
+
+.globl c
+.type  c,@function
+c:
+retq
diff --git a/test/ELF/verneed-as-needed-weak.s b/test/ELF/verneed-as-needed-weak.s
new file mode 100644 (file)
index 0000000..a8efdc4
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o --as-needed %S/Inputs/verneed1.so -o %t
+# RUN: llvm-readobj -V %t | FileCheck %s
+
+# CHECK:       SHT_GNU_verneed {
+# CHECK-NEXT:  }
+
+.weak f1
+
+.globl _start
+_start:
+.data
+.quad f1
diff --git a/test/ELF/verneed-local.s b/test/ELF/verneed-local.s
new file mode 100644 (file)
index 0000000..9ab6cd7
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o %S/Inputs/verneed1.so -o %t 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: f3
+# CHECK: >>> referenced by {{.*}}:(.text+0x1)
+.globl _start
+_start:
+call f3
diff --git a/test/ELF/verneed.s b/test/ELF/verneed.s
new file mode 100644 (file)
index 0000000..d0d0067
--- /dev/null
@@ -0,0 +1,173 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o %S/Inputs/verneed1.so %S/Inputs/verneed2.so -o %t
+# RUN: llvm-readobj -V -sections -section-data -dyn-symbols -dynamic-table %t | FileCheck %s
+
+# CHECK:        Section {
+# CHECK:         Index: 1
+# CHECK-NEXT:    Name: .dynsym
+# CHECK-NEXT:    Type: SHT_DYNSYM (0xB)
+# CHECK-NEXT:    Flags [ (0x2)
+# CHECK-NEXT:      SHF_ALLOC (0x2)
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Address: 0x2001C8
+# CHECK-NEXT:    Offset: 0x1C8
+# CHECK-NEXT:    Size: 96
+# CHECK-NEXT:    Link: 5
+# CHECK-NEXT:    Info: 1
+# CHECK-NEXT:    AddressAlignment: 8
+# CHECK-NEXT:    EntrySize: 24
+# CHECK:       Section {
+# CHECK-NEXT:   Index: 2
+# CHECK-NEXT:   Name: .gnu.version
+# CHECK-NEXT:   Type: SHT_GNU_versym (0x6FFFFFFF)
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x200228
+# CHECK-NEXT:   Offset: 0x228
+# CHECK-NEXT:   Size: 8
+# CHECK-NEXT:   Link: 1
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 2
+# CHECK-NEXT:   EntrySize: 2
+# CHECK:       Section {
+# CHECK-NEXT:   Index: 3
+# CHECK-NEXT:   Name: .gnu.version_r
+# CHECK-NEXT:   Type: SHT_GNU_verneed (0x6FFFFFFE)
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x200230
+# CHECK-NEXT:   Offset: 0x230
+# CHECK-NEXT:   Size: 80
+# CHECK-NEXT:   Link: 5
+# CHECK-NEXT:   Info: 2
+# CHECK-NEXT:   AddressAlignment: 4
+# CHECK-NEXT:   EntrySize: 0
+# CHECK:      Section {
+# CHECK:        Index: 5
+# CHECK-NEXT:   Name: .dynstr
+# CHECK-NEXT:   Type: SHT_STRTAB
+# CHECK-NEXT:   Flags [ (0x2)
+# CHECK-NEXT:     SHF_ALLOC (0x2)
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x2002A8
+# CHECK-NEXT:   Offset: 0x2A8
+# CHECK-NEXT:   Size: 47
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 0
+# CHECK-NEXT:   SectionData (
+# CHECK-NEXT:     0000: 00766572 6E656564 312E736F 2E300076  |.verneed1.so.0.v|
+# CHECK-NEXT:     0010: 65726E65 6564322E 736F2E30 00663100  |erneed2.so.0.f1.|
+# CHECK-NEXT:     0020: 76330066 32007632 00673100 763100    |v3.f2.v2.g1.v1.|
+# CHECK-NEXT:   )
+# CHECK-NEXT: }
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: f1@v3
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: f2@v2
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: g1@v1
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global (0x1)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# CHECK:      0x000000006FFFFFF0 VERSYM               0x200228
+# CHECK-NEXT: 0x000000006FFFFFFE VERNEED              0x200230
+# CHECK-NEXT: 0x000000006FFFFFFF VERNEEDNUM           2
+
+# CHECK:      Version symbols {
+# CHECK-NEXT:    Section Name: .gnu.version
+# CHECK-NEXT:    Address: 0x200228
+# CHECK-NEXT:    Offset: 0x228
+# CHECK-NEXT:    Link: 1
+# CHECK-NEXT:    Symbols [
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 0
+# CHECK-NEXT:        Name: @
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 2
+# CHECK-NEXT:        Name: f1@v3
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 3
+# CHECK-NEXT:        Name: f2@v2
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Symbol {
+# CHECK-NEXT:        Version: 4
+# CHECK-NEXT:        Name: g1@v1
+# CHECK-NEXT:      }
+# CHECK-NEXT:    ]
+# CHECK-NEXT:  }
+# CHECK-NEXT:  SHT_GNU_verdef {
+# CHECK-NEXT:  }
+# CHECK-NEXT:  SHT_GNU_verneed {
+# CHECK-NEXT:    Dependency {
+# CHECK-NEXT:      Version: 1
+# CHECK-NEXT:      Count: 2
+# CHECK-NEXT:      FileName: verneed1.so.0
+# CHECK-NEXT:      Entry {
+# CHECK-NEXT:        Hash: 1938
+# CHECK-NEXT:        Flags: 0x0
+# CHECK-NEXT:        Index: 3
+# CHECK-NEXT:        Name: v2
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Entry {
+# CHECK-NEXT:        Hash: 1939
+# CHECK-NEXT:        Flags: 0x0
+# CHECK-NEXT:        Index: 2
+# CHECK-NEXT:        Name: v3
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+# CHECK-NEXT:    Dependency {
+# CHECK-NEXT:      Version: 1
+# CHECK-NEXT:      Count: 1
+# CHECK-NEXT:      FileName: verneed2.so.0
+# CHECK-NEXT:      Entry {
+# CHECK-NEXT:        Hash: 1937
+# CHECK-NEXT:        Flags: 0x0
+# CHECK-NEXT:        Index: 4
+# CHECK-NEXT:        Name: v1
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+# CHECK-NEXT:  }
+
+.globl _start
+_start:
+call f1@plt
+call f2@plt
+call g1@plt
diff --git a/test/ELF/version-script-anonymous-local.s b/test/ELF/version-script-anonymous-local.s
new file mode 100644 (file)
index 0000000..3716b7a
--- /dev/null
@@ -0,0 +1,61 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: echo "{ global: foo; local: bar; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols -t %t.so | FileCheck %s
+
+# CHECK:      Symbols [
+# CHECK:          Name: bar
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Local
+
+# CHECK:          Name: foo
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+
+# CHECK:          Name: zed
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+
+
+# CHECK:       DynamicSymbols [
+# CHECK-NEXT:    Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding:
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: zed
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+
+.global foo
+foo:
+.global bar
+bar:
+.global zed
+zed:
diff --git a/test/ELF/version-script-complex-wildcards.s b/test/ELF/version-script-complex-wildcards.s
new file mode 100644 (file)
index 0000000..61e1069
--- /dev/null
@@ -0,0 +1,62 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "FOO { global: extern \"C++\" { ab[c]*; }; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABC
+# ABC: Name: _Z3abbi@
+# ABC: Name: _Z3abci@@FOO
+
+# RUN: echo "FOO { global: extern \"C++\" { ab[b]*; }; };" > %t1.script
+# RUN: ld.lld --version-script %t1.script -shared %t.o -o %t1.so
+# RUN: llvm-readobj -V %t1.so | FileCheck %s --check-prefix=ABB
+# ABB: Name: _Z3abbi@@FOO
+# ABB: Name: _Z3abci@
+
+# RUN: echo "FOO { global: extern \"C++\" { ab[a-b]*; }; };" > %t2.script
+# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so
+# RUN: llvm-readobj -V %t2.so | FileCheck %s --check-prefix=ABB
+
+# RUN: echo "FOO { global: extern \"C++\" { ab[a-c]*; }; };" > %t3.script
+# RUN: ld.lld --version-script %t3.script -shared %t.o -o %t3.so
+# RUN: llvm-readobj -V %t3.so | FileCheck %s --check-prefix=ABBABC
+# ABBABC: Name: _Z3abbi@@FOO
+# ABBABC: Name: _Z3abci@@FOO
+
+# RUN: echo "FOO { global: extern \"C++\" { ab[a-bc-d]*; }; };" > %t4.script
+# RUN: ld.lld --version-script %t4.script -shared %t.o -o %t4.so
+# RUN: llvm-readobj -V %t4.so | FileCheck %s --check-prefix=ABBABC
+
+# RUN: echo "FOO { global: extern \"C++\" { ab[a-bd-e]*; }; };" > %t5.script
+# RUN: ld.lld --version-script %t5.script -shared %t.o -o %t5.so
+# RUN: llvm-readobj -V %t5.so | FileCheck %s --check-prefix=ABB
+
+# RUN: echo "FOO { global: extern \"C++\" { ab[^a-c]*; }; };" > %t6.script
+# RUN: ld.lld --version-script %t6.script -shared %t.o -o %t6.so
+# RUN: llvm-readobj -V %t6.so | FileCheck %s --check-prefix=NO
+# NO:  Name: _Z3abbi@
+# NO:  Name: _Z3abci@
+
+# RUN: echo "FOO { global: extern \"C++\" { ab[^c-z]*; }; };" > %t7.script
+# RUN: ld.lld --version-script %t7.script -shared %t.o -o %t7.so
+# RUN: llvm-readobj -V %t7.so | FileCheck %s --check-prefix=ABB
+
+# RUN: echo "FOO { global: extern \"C++\" { a[x-za-b][a-c]*; }; };" > %t8.script
+# RUN: ld.lld --version-script %t8.script -shared %t.o -o %t8.so
+# RUN: llvm-readobj -V %t8.so | FileCheck %s --check-prefix=ABBABC
+
+# RUN: echo "FOO { global: extern \"C++\" { a[; }; };" > %t9.script
+# RUN: not ld.lld --version-script %t9.script -shared %t.o -o %t9.so 2>&1 \
+# RUN:   | FileCheck %s --check-prefix=ERROR
+# ERROR: invalid glob pattern: a[
+
+.text
+.globl _Z3abci
+.type _Z3abci,@function
+_Z3abci:
+retq
+
+.globl _Z3abbi
+.type _Z3abbi,@function
+_Z3abbi:
+retq
diff --git a/test/ELF/version-script-copy-rel.s b/test/ELF/version-script-copy-rel.s
new file mode 100644 (file)
index 0000000..42d922e
--- /dev/null
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-in-shared.s -o %t1.o
+# RUN: echo "FOOVER { global: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t1.o -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+# RUN: ld.lld %t2.o %t.so -o %tout
+# RUN: llvm-readobj -dyn-symbols %tout | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK:        Symbol {
+# CHECK:          Name: foo@FOOVER
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section: .bss.rel.ro
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.text
+.global _start
+_start:
+movl $0, foo
diff --git a/test/ELF/version-script-err.s b/test/ELF/version-script-err.s
new file mode 100644 (file)
index 0000000..ea3f664
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t.so --version-script %p/Inputs/version-script-err.script 2>&1 | FileCheck %s
+// CHECK: ; expected, but got }
+
+// RUN: echo    "\"" > %terr1.script
+// RUN: not ld.lld --version-script %terr1.script -shared %t.o -o %t.so 2>&1 | \
+// RUN:   FileCheck -check-prefix=ERR1 %s
+// ERR1: {{.*}}:1: unclosed quote
+// ERR1-NEXT: {{.*}}: unexpected EOF
diff --git a/test/ELF/version-script-extern-exact.s b/test/ELF/version-script-extern-exact.s
new file mode 100644 (file)
index 0000000..bfd44e5
--- /dev/null
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "FOO { global: extern \"C++\" { \"aaa*\"; }; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s --check-prefix=NOMATCH
+
+# NOMATCH:     DynamicSymbols [
+# NOMATCH-NOT:   _Z3aaaPf@@FOO
+# NOMATCH-NOT:   _Z3aaaPi@@FOO
+# NOMATCH:     ]
+
+# RUN: echo "FOO { global: extern \"C++\" { \"aaa*\"; aaa*; }; };" > %t2.script
+# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so
+# RUN: llvm-readobj -dyn-symbols %t2.so | FileCheck %s --check-prefix=MATCH
+# MATCH:   DynamicSymbols [
+# MATCH:     _Z3aaaPf@@FOO
+# MATCH:     _Z3aaaPi@@FOO
+# MATCH:   ]
+
+.text
+.globl _Z3aaaPi
+.type _Z3aaaPi,@function
+_Z3aaaPi:
+retq
+
+.globl _Z3aaaPf
+.type _Z3aaaPf,@function
+_Z3aaaPf:
+retq
diff --git a/test/ELF/version-script-extern-wildcards-anon.s b/test/ELF/version-script-extern-wildcards-anon.s
new file mode 100644 (file)
index 0000000..5ba2f7d
--- /dev/null
@@ -0,0 +1,74 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo '{ \
+# RUN:       global: \
+# RUN:       _Z3bari; \
+# RUN:       extern "C++" { \
+# RUN:         "foo(int)"; \
+# RUN:         z*; \
+# RUN:         std::q*; \
+# RUN:       }; \
+# RUN:       local: *; \
+# RUN:       }; ' > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _Z3bari
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _Z3fooi
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _Z3zedi
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: _ZSt3qux
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type:
+# CHECK-NEXT:     Other:
+# CHECK-NEXT:     Section:
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global _Z3fooi
+_Z3fooi:
+.global _Z3bari
+_Z3bari:
+.global _Z3zedi
+_Z3zedi:
+.global _Z3bazi
+_Z3bazi:
+.global _ZSt3qux
+_ZSt3qux:
diff --git a/test/ELF/version-script-extern-wildcards.s b/test/ELF/version-script-extern-wildcards.s
new file mode 100644 (file)
index 0000000..472fc1f
--- /dev/null
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "FOO { global: extern \"C++\" { foo*; }; };" > %t.script
+# RUN: echo "BAR { global: extern \"C++\" { zed*; bar; }; };" >> %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck %s
+
+# CHECK:  Version symbols {
+# CHECK:   Symbols [
+# CHECK:    Name: _Z3bari@
+# CHECK:    Name: _Z3fooi@@FOO
+# CHECK:    Name: _Z3zedi@@BAR
+
+.text
+.globl _Z3fooi
+.type _Z3fooi,@function
+_Z3fooi:
+retq
+
+.globl _Z3bari
+.type _Z3bari,@function
+_Z3bari:
+retq
+
+.globl _Z3zedi
+.type _Z3zedi,@function
+_Z3zedi:
+retq
diff --git a/test/ELF/version-script-extern.s b/test/ELF/version-script-extern.s
new file mode 100644 (file)
index 0000000..2b89839
--- /dev/null
@@ -0,0 +1,126 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "LIBSAMPLE_1.0 { global:" > %t.script
+# RUN: echo '  extern "C++" { "foo(int)"; "zed(int)"; "abc::abc()"; };' >> %t.script
+# RUN: echo "};" >> %t.script
+# RUN: echo "LIBSAMPLE_2.0 { global:" >> %t.script
+# RUN: echo '  extern "C" { _Z3bari; };' >> %t.script
+# RUN: echo "};" >> %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# DSO:      DynamicSymbols [
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: @
+# DSO-NEXT:      Value: 0x0
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Local
+# DSO-NEXT:      Type: None
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: Undefined
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3bari@@LIBSAMPLE_2.0
+# DSO-NEXT:      Value: 0x1001
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3fooi@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1000
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global
+# DSO-NEXT:      Type: Function
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _Z3zedi@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1002
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global (0x1)
+# DSO-NEXT:      Type: Function (0x2)
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text (0x6)
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _ZN3abcC1Ev@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1003
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global (0x1)
+# DSO-NEXT:      Type: Function (0x2)
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text (0x6)
+# DSO-NEXT:    }
+# DSO-NEXT:    Symbol {
+# DSO-NEXT:      Name: _ZN3abcC2Ev@@LIBSAMPLE_1.0
+# DSO-NEXT:      Value: 0x1004
+# DSO-NEXT:      Size: 0
+# DSO-NEXT:      Binding: Global (0x1)
+# DSO-NEXT:      Type: Function (0x2)
+# DSO-NEXT:      Other: 0
+# DSO-NEXT:      Section: .text (0x6)
+# DSO-NEXT:    }
+# DSO-NEXT:  ]
+# DSO-NEXT:  Version symbols {
+# DSO-NEXT:    Section Name: .gnu.version
+# DSO-NEXT:    Address: 0x258
+# DSO-NEXT:    Offset: 0x258
+# DSO-NEXT:    Link: 1
+# DSO-NEXT:    Symbols [
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 0
+# DSO-NEXT:        Name: @
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 3
+# DSO-NEXT:        Name: _Z3bari@@LIBSAMPLE_2.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3fooi@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _Z3zedi@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _ZN3abcC1Ev@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:      Symbol {
+# DSO-NEXT:        Version: 2
+# DSO-NEXT:        Name: _ZN3abcC2Ev@@LIBSAMPLE_1.0
+# DSO-NEXT:      }
+# DSO-NEXT:    ]
+# DSO-NEXT:  }
+
+.text
+.globl _Z3fooi
+.type _Z3fooi,@function
+_Z3fooi:
+retq
+
+.globl _Z3bari
+.type _Z3bari,@function
+_Z3bari:
+retq
+
+.globl _Z3zedi
+.type _Z3zedi,@function
+_Z3zedi:
+retq
+
+.globl _ZN3abcC1Ev
+.type _ZN3abcC1Ev,@function
+_ZN3abcC1Ev:
+retq
+
+.globl _ZN3abcC2Ev
+.type _ZN3abcC2Ev,@function
+_ZN3abcC2Ev:
+retq
diff --git a/test/ELF/version-script-glob.s b/test/ELF/version-script-glob.s
new file mode 100644 (file)
index 0000000..8149ead
--- /dev/null
@@ -0,0 +1,72 @@
+# REQUIRES: x86
+
+# RUN: echo "{ global: foo*; bar*; local: *; };" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -shared --version-script %t.script %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+        .globl foo1
+foo1:
+
+        .globl bar1
+bar1:
+
+        .globl zed1
+zed1:
+
+        .globl local
+local:
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: bar1
+# CHECK-NEXT:     Value: 0x1000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo1
+# CHECK-NEXT:     Value: 0x1000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# RUN: echo "{ global : local; local: *; };" > %t1.script
+# RUN: ld.lld -shared --version-script %t1.script %t.o -o %t1.so
+
+# LOCAL:      DynamicSymbols [
+# LOCAL-NEXT:   Symbol {
+# LOCAL-NEXT:     Name:
+# LOCAL-NEXT:     Value: 0x0
+# LOCAL-NEXT:     Size: 0
+# LOCAL-NEXT:     Binding: Local
+# LOCAL-NEXT:     Type: None
+# LOCAL-NEXT:     Other: 0
+# LOCAL-NEXT:     Section: Undefined
+# LOCAL-NEXT:   }
+# LOCAL-NEXT:   Symbol {
+# LOCAL-NEXT:     Name: local
+# LOCAL-NEXT:     Value: 0x1000
+# LOCAL-NEXT:     Size: 0
+# LOCAL-NEXT:     Binding: Global
+# LOCAL-NEXT:     Type: None
+# LOCAL-NEXT:     Other: 0
+# LOCAL-NEXT:     Section: .text
+# LOCAL-NEXT:   }
+# LOCAL-NEXT: ]
diff --git a/test/ELF/version-script-hide-so-symbol.s b/test/ELF/version-script-hide-so-symbol.s
new file mode 100644 (file)
index 0000000..b4f58be
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t2.so
+# RUN: echo "{ local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o %t2.so -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# The symbol foo must be hidden. This matches bfd and gold and is
+# required to make it possible for a c++ library to hide its own
+# operator delete.
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @ (0)
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+        .global foo
+foo:
+       nop
+
diff --git a/test/ELF/version-script-locals-extern.s b/test/ELF/version-script-locals-extern.s
new file mode 100644 (file)
index 0000000..12e8771
--- /dev/null
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "FOO { local: extern \"C++\" { \"abb(int)\"; }; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABB
+# ABB:      Symbols [
+# ABB-NEXT:   Symbol {
+# ABB-NEXT:     Version: 0
+# ABB-NEXT:     Name: @
+# ABB-NEXT:   }
+# ABB-NEXT:   Symbol {
+# ABB-NEXT:     Version: 1
+# ABB-NEXT:     Name: _Z3abci@
+# ABB-NEXT:   }
+# ABB-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "FOO { local: extern \"C++\" { abb*; }; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABB
+
+# RUN: echo "FOO { local: extern \"C++\" { abc*; }; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABC
+# ABC:      Symbols [
+# ABC-NEXT:   Symbol {
+# ABC-NEXT:     Version: 0
+# ABC-NEXT:     Name: @
+# ABC-NEXT:   }
+# ABC-NEXT:   Symbol {
+# ABC-NEXT:     Version: 1
+# ABC-NEXT:     Name: _Z3abbi@
+# ABC-NEXT:   }
+# ABC-NEXT: ]
+
+.globl _Z3abbi
+.type _Z3abbi,@function
+_Z3abbi:
+retq
+
+.globl _Z3abci
+.type _Z3abci,@function
+_Z3abci:
+retq
diff --git a/test/ELF/version-script-locals.s b/test/ELF/version-script-locals.s
new file mode 100644 (file)
index 0000000..80110c3
--- /dev/null
@@ -0,0 +1,45 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "VERSION_1.0 { local: foo1; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=EXACT %s
+# EXACT:  DynamicSymbols [
+# EXACT:      _start
+# EXACT-NOT:  foo1
+# EXACT:      foo2
+# EXACT:      foo3
+
+# RUN: echo "VERSION_1.0 { local: foo*; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=WC %s
+# WC:  DynamicSymbols [
+# WC:      _start
+# WC-NOT:  foo1
+# WC-NOT:  foo2
+# WC-NOT:  foo3
+
+# RUN: echo "VERSION_1.0 { global: *; local: foo*; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=MIX %s
+# MIX:  DynamicSymbols [
+# MIX:      _start@@VERSION_1.0
+# MIX-NOT:  foo1
+# MIX-NOT:  foo2
+# MIX-NOT:  foo3
+
+.globl foo1
+foo1:
+  ret
+
+.globl foo2
+foo2:
+  ret
+
+.globl foo3
+foo3:
+  ret
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/version-script-missing.s b/test/ELF/version-script-missing.s
new file mode 100644 (file)
index 0000000..ad4786e
--- /dev/null
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+
+# We used to crash if a symbol in a version script was not in the symbol table.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "{ foobar; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
diff --git a/test/ELF/version-script-no-warn.s b/test/ELF/version-script-no-warn.s
new file mode 100644 (file)
index 0000000..6a89715
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so
+
+# RUN: echo "foo { global: bar;  local: *; };" > %t.script
+# RUN: ld.lld --fatal-warnings --shared --version-script %t.script %t.o %t2.so
+
+.global bar
+bar:
+        nop
diff --git a/test/ELF/version-script-no-warn2.s b/test/ELF/version-script-no-warn2.s
new file mode 100644 (file)
index 0000000..52beff3
--- /dev/null
@@ -0,0 +1,8 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/version-script-no-warn2.s -o %t1.o
+# RUN: ld.lld %t1.o -o %t1.so -shared
+# RUN: echo "{ global: foo; local:  *; };" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+# RUN: ld.lld -shared --version-script %t.script %t2.o %t1.so -o %t2.so --fatal-warnings
+
+.global        foo
+foo:
diff --git a/test/ELF/version-script-noundef.s b/test/ELF/version-script-noundef.s
new file mode 100644 (file)
index 0000000..247752c
--- /dev/null
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: echo "VERSION_1.0 { global: bar; };" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld --version-script %t.script -shared --no-undefined-version \
+# RUN:   %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR1 %s
+# ERR1: version script assignment of 'VERSION_1.0' to symbol 'bar' failed: symbol not defined
+
+# RUN: echo "VERSION_1.0 { global: und; };" > %t2.script
+# RUN: not ld.lld --version-script %t2.script -shared --no-undefined-version \
+# RUN:   %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR2 %s
+# ERR2: version script assignment of 'VERSION_1.0' to symbol 'und' failed: symbol not defined
+
+# RUN: echo "VERSION_1.0 { local: und; };" > %t3.script
+# RUN: not ld.lld --version-script %t3.script -shared --no-undefined-version \
+# RUN:   %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR3 %s
+# ERR3: version script assignment of 'local' to symbol 'und' failed: symbol not defined
+
+.text
+.globl foo
+.type foo,@function
+foo:
+callq und@PLT
diff --git a/test/ELF/version-script-symver.s b/test/ELF/version-script-symver.s
new file mode 100644 (file)
index 0000000..0a4eddd
--- /dev/null
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+
+.global _start
+.global bar
+.symver _start, bar@@VERSION
+_start:
+  jmp bar
diff --git a/test/ELF/version-script-symver2.s b/test/ELF/version-script-symver2.s
new file mode 100644 (file)
index 0000000..5961d9a
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "VER1 { global: foo; local: *; }; VER2 { global: foo; }; VER3 { global: foo; };" > %t.map
+# RUN: ld.lld -shared %t.o --version-script %t.map -o %t.so --fatal-warnings
+# RUN: llvm-readobj -V %t.so | FileCheck %s
+
+# CHECK:      Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Version: 0
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Version: 3
+# CHECK-NEXT:     Name: foo@@VER2
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Version: 2
+# CHECK-NEXT:     Name: foo@VER1
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global bar
+bar:
+.symver bar, foo@VER1
+
+.global zed
+zed:
+.symver zed, foo@@VER2
diff --git a/test/ELF/version-script-twice.s b/test/ELF/version-script-twice.s
new file mode 100644 (file)
index 0000000..3aeedd5
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+
+# RUN: echo "FBSD_1.1 {}; FBSD_1.2 {};" > %t.ver
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so --version-script=%t.ver
+# RUN: llvm-readobj --dyn-symbols --elf-output-style=GNU %t.so | FileCheck %s
+
+        .weak  openat
+openat:
+openat@FBSD_1.1 = openat
+openat@@FBSD_1.2 = openat
+
+# CHECK-DAG: openat@FBSD_1.1
+# CHECK-DAG: openat@@FBSD_1.2
diff --git a/test/ELF/version-script-undef-version.s b/test/ELF/version-script-undef-version.s
new file mode 100644 (file)
index 0000000..40dc816
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+
+# Test that we don't error on undefined versions when static linking.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: echo "DEFINED { global: *; };" > %t.map
+# RUN: ld.lld %t.o --version-script %t.map -o %t
+
+.global _start
+.global bar
+.symver _start, bar@@UNDEFINED
+_start:
diff --git a/test/ELF/version-script-weak.s b/test/ELF/version-script-weak.s
new file mode 100644 (file)
index 0000000..cc3df8d
--- /dev/null
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/version-script-weak.s -o %tmp.o
+# RUN: rm -f %t.a
+# RUN: llvm-ar rcs %t.a %tmp.o
+# RUN: echo "{ local: *; };" > %t.script
+# RUN: ld.lld -shared --version-script %t.script %t.o %t.a -o %t.so
+# RUN: llvm-readobj -dyn-symbols -r %t.so | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.plt {
+# CHECK-NEXT:     0x2018 R_X86_64_JUMP_SLOT foo
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+# CHECK:      Symbol {
+# CHECK:        Name: foo@
+# CHECK-NEXT:   Value: 0x0
+# CHECK-NEXT:   Size: 0
+# CHECK-NEXT:   Binding: Weak
+# CHECK-NEXT:   Type: None
+# CHECK-NEXT:   Other: 0
+# CHECK-NEXT:   Section: Undefined
+# CHECK-NEXT: }
+
+.text
+ callq foo@PLT
+.weak foo
diff --git a/test/ELF/version-script.s b/test/ELF/version-script.s
new file mode 100644 (file)
index 0000000..72f9eeb
--- /dev/null
@@ -0,0 +1,226 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so
+
+# RUN: echo "{ global: foo1; foo3; local: *; };" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --version-script %t.script -shared %t.o %t2.so -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s
+
+# RUN: echo "# comment" > %t3.script
+# RUN: echo "{ local: *; # comment" >> %t3.script
+# RUN: echo -n "}; # comment" >> %t3.script
+# RUN: ld.lld --version-script %t3.script -shared %t.o %t2.so -o %t3.so
+# RUN: llvm-readobj -dyn-symbols %t3.so | FileCheck --check-prefix=DSO2 %s
+
+## Also check that both "global:" and "global :" forms are accepted
+# RUN: echo "VERSION_1.0 { global : foo1; local : *; };" > %t4.script
+# RUN: echo "VERSION_2.0 { global: foo3; local: *; };" >> %t4.script
+# RUN: ld.lld --version-script %t4.script -shared %t.o %t2.so -o %t4.so
+# RUN: llvm-readobj -dyn-symbols %t4.so | FileCheck --check-prefix=VERDSO %s
+
+# RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t5.script
+# RUN: echo "{ global: foo3; local: *; };" >> %t5.script
+# RUN: not ld.lld --version-script %t5.script -shared %t.o %t2.so -o %t5.so 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR1 %s
+# ERR1: anonymous version definition is used in combination with other version definitions
+
+# RUN: echo "{ global: foo1; local: *; };" > %t5.script
+# RUN: echo "VERSION_2.0 { global: foo3; local: *; };" >> %t5.script
+# RUN: not ld.lld --version-script %t5.script -shared %t.o %t2.so -o %t5.so 2>&1 | \
+# RUN:   FileCheck -check-prefix=ERR2 %s
+# ERR2: EOF expected, but got VERSION_2.0
+
+# RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t6.script
+# RUN: echo "VERSION_2.0 { global: foo1; local: *; };" >> %t6.script
+# RUN: ld.lld --version-script %t6.script -shared %t.o %t2.so -o %t6.so 2>&1 | \
+# RUN:   FileCheck -check-prefix=WARN2 %s
+# WARN2: duplicate symbol 'foo1' in version script
+
+# RUN: echo "{ foo1; foo2; };" > %t.list
+# RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2
+# RUN: llvm-readobj %t2 > /dev/null
+
+# DSO:      DynamicSymbols [
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: @
+# DSO-NEXT:     Value: 0x0
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Local (0x0)
+# DSO-NEXT:     Type: None (0x0)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: Undefined (0x0)
+# DSO-NEXT:   }
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: bar@
+# DSO-NEXT:     Value: 0x0
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Global (0x1)
+# DSO-NEXT:     Type: Function (0x2)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: Undefined (0x0)
+# DSO-NEXT:   }
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: foo1@
+# DSO-NEXT:     Value: 0x1000
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Global (0x1)
+# DSO-NEXT:     Type: None (0x0)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: .text
+# DSO-NEXT:   }
+# DSO-NEXT:   Symbol {
+# DSO-NEXT:     Name: foo3@
+# DSO-NEXT:     Value: 0x1007
+# DSO-NEXT:     Size: 0
+# DSO-NEXT:     Binding: Global (0x1)
+# DSO-NEXT:     Type: None (0x0)
+# DSO-NEXT:     Other: 0
+# DSO-NEXT:     Section: .text
+# DSO-NEXT:   }
+# DSO-NEXT: ]
+
+# DSO2:      DynamicSymbols [
+# DSO2-NEXT:   Symbol {
+# DSO2-NEXT:     Name: @
+# DSO2-NEXT:     Value: 0x0
+# DSO2-NEXT:     Size: 0
+# DSO2-NEXT:     Binding: Local (0x0)
+# DSO2-NEXT:     Type: None (0x0)
+# DSO2-NEXT:     Other: 0
+# DSO2-NEXT:     Section: Undefined (0x0)
+# DSO2-NEXT:   }
+# DSO2-NEXT:   Symbol {
+# DSO2-NEXT:     Name: bar@
+# DSO2-NEXT:     Value: 0x0
+# DSO2-NEXT:     Size: 0
+# DSO2-NEXT:     Binding: Global (0x1)
+# DSO2-NEXT:     Type: Function (0x2)
+# DSO2-NEXT:     Other: 0
+# DSO2-NEXT:     Section: Undefined (0x0)
+# DSO2-NEXT:   }
+# DSO2-NEXT: ]
+
+# VERDSO:      DynamicSymbols [
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: @
+# VERDSO-NEXT:     Value: 0x0
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Local
+# VERDSO-NEXT:     Type: None
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: Undefined
+# VERDSO-NEXT:   }
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: bar@
+# VERDSO-NEXT:     Value: 0x0
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Global
+# VERDSO-NEXT:     Type: Function
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: Undefined
+# VERDSO-NEXT:   }
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: foo1@@VERSION_1.0
+# VERDSO-NEXT:     Value: 0x1000
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Global
+# VERDSO-NEXT:     Type: None
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: .text
+# VERDSO-NEXT:   }
+# VERDSO-NEXT:   Symbol {
+# VERDSO-NEXT:     Name: foo3@@VERSION_2.0
+# VERDSO-NEXT:     Value: 0x1007
+# VERDSO-NEXT:     Size: 0
+# VERDSO-NEXT:     Binding: Global
+# VERDSO-NEXT:     Type: None
+# VERDSO-NEXT:     Other: 0
+# VERDSO-NEXT:     Section: .text
+# VERDSO-NEXT:   }
+# VERDSO-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o %t2.so -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=ALL %s
+
+# RUN: echo "{ global: foo1; foo3; };" > %t2.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --version-script %t2.script -shared %t.o %t2.so -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=ALL %s
+
+# ALL:      DynamicSymbols [
+# ALL-NEXT:   Symbol {
+# ALL-NEXT:     Name: @
+# ALL-NEXT:     Value: 0x0
+# ALL-NEXT:     Size: 0
+# ALL-NEXT:     Binding: Local
+# ALL-NEXT:     Type: None
+# ALL-NEXT:     Other: 0
+# ALL-NEXT:     Section: Undefined
+# ALL-NEXT:   }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: _start@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: bar@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: Function
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: Undefined
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: foo1@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: foo2@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT:  Symbol {
+# ALL-NEXT:    Name: foo3@
+# ALL-NEXT:    Value:
+# ALL-NEXT:    Size: 0
+# ALL-NEXT:    Binding: Global
+# ALL-NEXT:    Type: None
+# ALL-NEXT:    Other: 0
+# ALL-NEXT:    Section: .text
+# ALL-NEXT:  }
+# ALL-NEXT: ]
+
+.globl foo1
+foo1:
+  call bar@PLT
+  ret
+
+.globl foo2
+foo2:
+  ret
+
+.globl foo3
+foo3:
+  call foo2@PLT
+  ret
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/version-symbol-error.s b/test/ELF/version-symbol-error.s
new file mode 100644 (file)
index 0000000..fb83b35
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: echo "V1 {};" > %t.script
+// RUN: not ld.lld -shared -version-script=%t.script %t.o -o %t.so 2>&1 \
+// RUN:   | FileCheck %s
+
+// CHECK: .o: symbol foo@V2 has undefined version V2
+
+.globl foo@V2
+.text
+foo@V2:
+  ret
diff --git a/test/ELF/version-undef-sym.s b/test/ELF/version-undef-sym.s
new file mode 100644 (file)
index 0000000..20e92e6
--- /dev/null
@@ -0,0 +1,42 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-readobj --dyn-symbols %p/Inputs/version-undef-sym.so | FileCheck %s
+
+
+// Inputs/version-undef-sym.so consists of the assembly file
+//
+//         .global bar
+// bar:
+//        .weak abc1
+//        .weak abc2
+//        .weak abc3
+//        .weak abc4
+//        .weak abc5
+//
+// linked into a shared library with the version script
+//
+// VER_1 {
+// global:
+//   bar;
+// };
+//
+// Assuming we can reproduce the desired property (a few undefined symbols
+// before bar) we should create it with lld itself once it supports that.
+
+
+// Show that the input .so has undefined symbols before bar. That is what would
+// get our version parsing out of sync.
+
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Section: Undefined
+// CHECK: Name: bar
+
+// But now we can successfully find bar.
+// RUN: ld.lld %t.o %p/Inputs/version-undef-sym.so -o %t.exe
+
+        .global _start
+_start:
+        call bar@plt
diff --git a/test/ELF/version-use.s b/test/ELF/version-use.s
new file mode 100644 (file)
index 0000000..7ef12bc
--- /dev/null
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o %p/Inputs/version-use.so -o %t.so -shared -z defs
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+
+        call    bar@PLT
+
+// CHECK-NOT: SHT_GNU_versym
diff --git a/test/ELF/version-wildcard.test b/test/ELF/version-wildcard.test
new file mode 100644 (file)
index 0000000..ac0b7ed
--- /dev/null
@@ -0,0 +1,108 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "VERSION_1.0 { global: foo*; local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo1@@VERSION_1.0
+# CHECK-NEXT:     Value: 0x1000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo2@@VERSION_1.0
+# CHECK-NEXT:     Value: 0x1001
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo3@@VERSION_1.0
+# CHECK-NEXT:     Value: 0x1007
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "VERSION_1.0 { global: foo2; local: *; };" > %t2.script
+# RUN: echo "VERSION_2.0 { global: foo*; };" >> %t2.script
+# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so
+# RUN: llvm-readobj -dyn-symbols %t2.so | FileCheck --check-prefix=MIX %s
+
+# MIX:      DynamicSymbols [
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: @
+# MIX-NEXT:     Value: 0x0
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Local
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: Undefined
+# MIX-NEXT:   }
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: foo1@@VERSION_2.0
+# MIX-NEXT:     Value: 0x1000
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Global
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: .text
+# MIX-NEXT:   }
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: foo2@@VERSION_1.0
+# MIX-NEXT:     Value: 0x1001
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Global
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: .text
+# MIX-NEXT:   }
+# MIX-NEXT:   Symbol {
+# MIX-NEXT:     Name: foo3@@VERSION_2.0
+# MIX-NEXT:     Value: 0x1007
+# MIX-NEXT:     Size: 0
+# MIX-NEXT:     Binding: Global
+# MIX-NEXT:     Type: None
+# MIX-NEXT:     Other: 0
+# MIX-NEXT:     Section: .text
+# MIX-NEXT:   }
+# MIX-NEXT: ]
+
+.globl foo1
+foo1:
+  ret
+
+.globl foo2
+foo2:
+  call foo1@PLT
+  ret
+
+.globl foo3
+foo3:
+  call foo2@PLT
+  ret
+
+.globl _start
+_start:
+  ret
diff --git a/test/ELF/visibility.s b/test/ELF/visibility.s
new file mode 100644 (file)
index 0000000..7af29c9
--- /dev/null
@@ -0,0 +1,129 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2
+// RUN: ld.lld -shared %t %t2 -o %t3
+// RUN: llvm-readobj -t -dyn-symbols %t3 | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Symbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name:
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: hidden
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: internal
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x1)
+// CHECK-NEXT:       STV_INTERNAL
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected_with_hidden
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: _DYNAMIC
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x2)
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .dynamic
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: default
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x3)
+// CHECK-NEXT:       STV_PROTECTED
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// CHECK:      DynamicSymbols [
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: @
+// CHECK-NEXT:     Value: 0x0
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: Undefined
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: default
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other: 0
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: protected
+// CHECK-NEXT:     Value:
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Global
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [ (0x3)
+// CHECK-NEXT:       STV_PROTECTED
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .text
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global default
+default:
+
+.global protected
+protected:
+
+.global hidden
+hidden:
+
+.global internal
+internal:
+
+.global protected_with_hidden
+.protected
+protected_with_hidden:
diff --git a/test/ELF/warn-common.s b/test/ELF/warn-common.s
new file mode 100644 (file)
index 0000000..783a9ab
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/warn-common.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/warn-common2.s -o %t3.o
+
+## Report multiple commons if warn-common is specified
+# RUN: ld.lld --warn-common %t1.o %t2.o -o %t.out 2>&1 | FileCheck %s --check-prefix=WARN
+# WARN: multiple common of arr
+
+## no-warn-common is ignored
+# RUN: ld.lld --no-warn-common %t1.o %t2.o -o %t.out
+# RUN: llvm-readobj %t.out > /dev/null
+
+## Report if common is overridden
+# RUN: ld.lld --warn-common %t1.o %t3.o -o %t.out 2>&1 | FileCheck %s --check-prefix=OVER
+# OVER: common arr is overridden
+
+## Report if common is overridden, but in different order
+# RUN: ld.lld --warn-common %t3.o %t1.o -o %t.out 2>&1 | FileCheck %s --check-prefix=OVER
+
+.globl _start
+_start:
+
+.type arr,@object
+.comm arr,4,4
diff --git a/test/ELF/warn-unresolved-symbols-hidden.s b/test/ELF/warn-unresolved-symbols-hidden.s
new file mode 100644 (file)
index 0000000..04691f9
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t.so -z defs --warn-unresolved-symbols 2>&1| FileCheck %s
+
+# CHECK: warning: undefined symbol: foo
+# CHECK: error: undefined symbol: bar
+# CHECK: error: undefined symbol: zed
+
+.data
+.quad foo
+.hidden bar
+.quad bar
+.protected zed
+.quad zed
diff --git a/test/ELF/warn-unresolved-symbols.s b/test/ELF/warn-unresolved-symbols.s
new file mode 100644 (file)
index 0000000..3342c6c
--- /dev/null
@@ -0,0 +1,51 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+
+## The link should fail with an undef error by default
+# RUN: not ld.lld %t1.o -o %t3 2>&1 | \
+# RUN: FileCheck -check-prefix=ERRUND %s
+
+## --error-unresolved-symbols should generate an error
+# RUN: not ld.lld %t1.o -o %t4 --error-unresolved-symbols 2>&1 | \
+# RUN: FileCheck -check-prefix=ERRUND %s
+
+## --warn-unresolved-symbols should generate a warning
+# RUN: ld.lld %t1.o -o %t5 --warn-unresolved-symbols 2>&1 | \
+# RUN: FileCheck -check-prefix=WARNUND %s
+
+## Test that the last option wins
+# RUN: ld.lld %t1.o -o %t5 --error-unresolved-symbols --warn-unresolved-symbols 2>&1 | \
+# RUN:  FileCheck -check-prefix=WARNUND %s
+# RUN: not ld.lld %t1.o -o %t6 --warn-unresolved-symbols --error-unresolved-symbols 2>&1 | \
+# RUN:  FileCheck -check-prefix=ERRUND %s
+
+## Do not report undefines if linking relocatable or shared.
+## And while we're at it, check that we can accept single -
+## variants of these options.
+# RUN: ld.lld -r %t1.o -o %t7 -error-unresolved-symbols 2>&1 | \
+# RUN:  FileCheck -allow-empty -check-prefix=NOERR %s
+# RUN: ld.lld -shared %t1.o -o %t8.so --error-unresolved-symbols 2>&1 | \
+# RUN:  FileCheck -allow-empty -check-prefix=NOERR %s
+# RUN: ld.lld -r %t1.o -o %t9 -warn-unresolved-symbols 2>&1 | \
+# RUN:  FileCheck -allow-empty -check-prefix=NOWARN %s
+# RUN: ld.lld -shared %t1.o -o %t10.so --warn-unresolved-symbols 2>&1 | \
+# RUN:  FileCheck -allow-empty -check-prefix=NOWARN %s
+
+# ERRUND: error: undefined symbol: undef
+# ERRUND: >>> referenced by {{.*}}:(.text+0x1)
+
+# WARNUND: warning: undefined symbol: undef
+# WARNUND: >>> referenced by {{.*}}:(.text+0x1)
+
+# NOERR-NOT: error: undefined symbol: undef
+# NOERR-NOT: >>> referenced by {{.*}}:(.text+0x1)
+
+# NOWARN-NOT: warning: undefined symbol: undef
+# NOWARN-NOT: >>> referenced by {{.*}}:(.text+0x1)
+
+.globl _start
+_start:
+
+.globl _shared
+_shared:
+ callq undef@PLT
diff --git a/test/ELF/weak-and-strong-undef.s b/test/ELF/weak-and-strong-undef.s
new file mode 100644 (file)
index 0000000..db93470
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/weak-and-strong-undef.s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld %t2.o %t1.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: error: undefined symbol: foo
+
+.long foo
+.globl _start
+_start:
+ret
diff --git a/test/ELF/weak-undef-hidden.s b/test/ELF/weak-undef-hidden.s
new file mode 100644 (file)
index 0000000..70b951b
--- /dev/null
@@ -0,0 +1,29 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+.data
+.weak g
+.hidden g
+.quad g
+
+// CHECK:      Name: .data
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 1
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000 00000000
+// CHECK-NEXT: )
+
+// CHECK:      Relocations [
+// CHECK-NEXT: ]
diff --git a/test/ELF/weak-undef-shared.s b/test/ELF/weak-undef-shared.s
new file mode 100644 (file)
index 0000000..668a05b
--- /dev/null
@@ -0,0 +1,19 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: llvm-mc %p/Inputs/shared.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t.exe
+// RUN: llvm-readobj -t %t.exe | FileCheck %s
+
+// CHECK:      Name: bar
+// CHECK-NEXT: Value: 0x201020
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Weak
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+.global _start
+_start:
+        .weak bar
+        .quad bar
diff --git a/test/ELF/weak-undef.s b/test/ELF/weak-undef.s
new file mode 100644 (file)
index 0000000..b634033
--- /dev/null
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: @
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local (0x0)
+# CHECK-NEXT:     Type: None (0x0)
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined (0x0)
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.weak foo
+
+.globl _start
+_start:
diff --git a/test/ELF/whole-archive.s b/test/ELF/whole-archive.s
new file mode 100644 (file)
index 0000000..c65f116
--- /dev/null
@@ -0,0 +1,40 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/whole-archive.s -o %ta.o
+// RUN: rm -f %t.a
+// RUN: llvm-ar rcs %t.a %ta.o
+
+// Should not add symbols from the archive by default as they are not required
+// RUN: ld.lld -o %t3 %t.o %t.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s
+// NOTADDED: Symbols [
+// NOTADDED-NOT: Name: _bar
+// NOTADDED: ]
+
+// Should add symbols from the archive if --whole-archive is used
+// RUN: ld.lld -o %t3 %t.o --whole-archive %t.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+// ADDED: Symbols [
+// ADDED: Name: _bar
+// ADDED: ]
+
+// --no-whole-archive should restore default behaviour
+// RUN: ld.lld -o %t3 %t.o --whole-archive --no-whole-archive %t.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s
+
+// --whole-archive and --no-whole-archive should affect only archives which follow them
+// RUN: ld.lld -o %t3 %t.o %t.a --whole-archive --no-whole-archive
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s
+// RUN: ld.lld -o %t3 %t.o --whole-archive %t.a --no-whole-archive
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+
+// --whole-archive should also work with thin archives
+// RUN: rm -f %tthin.a
+// RUN: llvm-ar --format=gnu rcsT %tthin.a %ta.o
+// RUN: ld.lld -o %t3 %t.o --whole-archive %tthin.a
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+
+.globl _start
+_start:
diff --git a/test/ELF/wrap-dynamic-undef.s b/test/ELF/wrap-dynamic-undef.s
new file mode 100644 (file)
index 0000000..95b9859
--- /dev/null
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap-dynamic-undef.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: ld.lld %t1.o %t2.so -o %t --wrap foo
+# RUN: llvm-readobj -dyn-symbols --elf-output-style=GNU %t | FileCheck %s
+
+# Test that the dynamic relocation uses foo. We used to produce a
+# relocation with __real_foo.
+
+# CHECK: NOTYPE  GLOBAL DEFAULT UND foo
+
+.global _start
+_start:
+       callq   __real_foo@plt
diff --git a/test/ELF/wrap.s b/test/ELF/wrap.s
new file mode 100644 (file)
index 0000000..3e75fdb
--- /dev/null
@@ -0,0 +1,31 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap.s -o %t2
+
+// RUN: ld.lld -o %t3 %t %t2 -wrap foo -wrap nosuchsym
+// RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s
+// RUN: ld.lld -o %t3 %t %t2 --wrap foo -wrap=nosuchsym
+// RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s
+
+// CHECK: _start:
+// CHECK-NEXT: movl $0x11010, %edx
+// CHECK-NEXT: movl $0x11010, %edx
+// CHECK-NEXT: movl $0x11000, %edx
+
+// This shows an oddity of our implementation. The symbol foo gets
+// mapped to __wrap_foo, but stays in the symbol table. This results
+// in it showing up twice in the output.
+
+// RUN: llvm-readobj -t -s %t3 | FileCheck -check-prefix=SYM %s
+// SYM:      Name: foo
+// SYM-NEXT: Value: 0x11000
+// SYM:      Name: __wrap_foo
+// SYM-NEXT: Value: 0x11010
+// SYM:      Name: __wrap_foo
+// SYM-NEXT: Value: 0x11010
+
+.global _start
+_start:
+  movl $foo, %edx
+  movl $__wrap_foo, %edx
+  movl $__real_foo, %edx
diff --git a/test/ELF/writable-merge.s b/test/ELF/writable-merge.s
new file mode 100644 (file)
index 0000000..3006fa3
--- /dev/null
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: writable SHF_MERGE section is not supported
+
+.section .foo,"awM",@progbits,4
+.quad 0
diff --git a/test/ELF/x86-64-dyn-rel-error.s b/test/ELF/x86-64-dyn-rel-error.s
new file mode 100644 (file)
index 0000000..ee39e2c
--- /dev/null
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld %t2.o -shared -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+        .global _start
+_start:
+        .data
+        .long bar
+
+// CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC
diff --git a/test/ELF/x86-64-dyn-rel-error2.s b/test/ELF/x86-64-dyn-rel-error2.s
new file mode 100644 (file)
index 0000000..e316aea
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld %t2.o -shared -o %t2.so
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+// CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC
+// CHECK: >>> defined in {{.*}}.so
+// CHECK: >>> referenced by {{.*}}.o:(.data+0x0)
+
+        .global _start
+_start:
+        .data
+        .long bar - .
diff --git a/test/ELF/x86-64-rela.s b/test/ELF/x86-64-rela.s
new file mode 100644 (file)
index 0000000..41bdd76
--- /dev/null
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux-gnux32 %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s
+
+        call foo@plt
+
+// CHECK:  0x{{0+}}14 PLTREL{{ +}}RELA
diff --git a/test/ELF/x86-64-relax-got-abs.s b/test/ELF/x86-64-relax-got-abs.s
new file mode 100644 (file)
index 0000000..c429120
--- /dev/null
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux %s \
+// RUN:   -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+// We used to fail trying to relax this into a pc relocation to an absolute
+// value.
+
+// CHECK: movq  4185(%rip), %rax
+
+       movq    bar@GOTPCREL(%rip), %rax
+        .data
+        .global bar
+        .hidden bar
+        bar = 42
diff --git a/test/ELF/x86-64-relax-offset.s b/test/ELF/x86-64-relax-offset.s
new file mode 100644 (file)
index 0000000..a7c7ce6
--- /dev/null
@@ -0,0 +1,13 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux %s \
+// RUN:   -o %t.o
+// RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux \
+// RUN:   %p/Inputs/x86-64-relax-offset.s -o %t2.o
+// RUN: ld.lld %t2.o %t.o -o %t.so -shared
+// RUN: llvm-objdump -d %t.so | FileCheck %s
+
+        mov foo@gotpcrel(%rip), %rax
+        nop
+
+// CHECK:      1004: {{.*}} leaq    -11(%rip), %rax
+// CHECK-NEXT: 100b: {{.*}} nop
diff --git a/test/ELF/x86-64-reloc-16.s b/test/ELF/x86-64-reloc-16.s
new file mode 100644 (file)
index 0000000..2954d99
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld -shared %t %t1 -o %t3
+
+// CHECK:      Contents of section .text:
+// CHECK-NEXT:   200000 42
+
+// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
+// ERROR: relocation R_X86_64_16 out of range
+
+.short foo
diff --git a/test/ELF/x86-64-reloc-32-fpic.s b/test/ELF/x86-64-reloc-32-fpic.s
new file mode 100644 (file)
index 0000000..e3e7c68
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC
+# CHECK: >>> defined in {{.*}}
+# CHECK: >>> referenced by {{.*}}:(.data+0x0)
+
+.data
+.long _shared
diff --git a/test/ELF/x86-64-reloc-8.s b/test/ELF/x86-64-reloc-8.s
new file mode 100644 (file)
index 0000000..1c3831f
--- /dev/null
@@ -0,0 +1,14 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8-error.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld -shared %t %t1 -o %t3
+
+// CHECK:      Contents of section .text:
+// CHECK-NEXT:   200000 42
+
+// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s
+// ERROR: relocation R_X86_64_8 out of range
+
+.byte foo
diff --git a/test/ELF/x86-64-reloc-error.s b/test/ELF/x86-64-reloc-error.s
new file mode 100644 (file)
index 0000000..ece1bd4
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-error.s -o %tabs
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld -shared %tabs %t -o %t2 2>&1 | FileCheck %s
+// REQUIRES: x86
+
+  movl $big, %edx
+  movq $foo - 0x1000000000000, %rdx
+
+# CHECK: {{.*}}:(.text+0x1): relocation R_X86_64_32 out of range
+# CHECK: {{.*}}:(.text+0x8): relocation R_X86_64_32S out of range
diff --git a/test/ELF/x86-64-reloc-pc32-fpic.s b/test/ELF/x86-64-reloc-pc32-fpic.s
new file mode 100644 (file)
index 0000000..399bf60
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC
+# CHECK: >>> defined in {{.*}}
+# CHECK: >>> referenced by {{.*}}:(.data+0x1)
+
+.data
+call _shared
diff --git a/test/ELF/x86-64-reloc-range.s b/test/ELF/x86-64-reloc-range.s
new file mode 100644 (file)
index 0000000..08f604e
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+// CHECK: {{.*}}:(.text+0x3): relocation R_X86_64_PC32 out of range
+// CHECK-NOT: relocation
+
+        lea     foo(%rip), %rax
+        lea     foo(%rip), %rax
+
+        .hidden foo
+        .bss
+        .zero 0x7fffe007
+foo:
diff --git a/test/ELF/x86-64-reloc-tpoff32-fpic.s b/test/ELF/x86-64-reloc-tpoff32-fpic.s
new file mode 100644 (file)
index 0000000..5be3dc3
--- /dev/null
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -shared -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: relocation R_X86_64_TPOFF32 cannot be used against shared object; recompile with -fPIC
+# CHECK: >>> defined in {{.*}}.o
+# CHECK: >>> referenced by {{.*}}.o:(.tdata+0xC)
+
+.section ".tdata", "awT", @progbits
+.globl var
+var:
+
+movq %fs:0, %rax
+leaq var@TPOFF(%rax),%rax
diff --git a/test/ELF/x86-64-tls-gd-got.s b/test/ELF/x86-64-tls-gd-got.s
new file mode 100644 (file)
index 0000000..f86c3aa
--- /dev/null
@@ -0,0 +1,19 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/x86-64-tls-gd-got.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+        .globl  _start
+_start:
+        .byte   0x66
+        leaq    bar@tlsgd(%rip), %rdi
+        .byte   0x66
+        rex64
+        call    *__tls_get_addr@GOTPCREL(%rip)
+        ret
+
+// CHECK:      _start:
+// CHECK-NEXT:   movq    %fs:0, %rax
+// CHECK-NEXT:   leaq    -4(%rax), %rax
+// CHECK-NEXT:   retq
diff --git a/test/ELF/x86-64-tls-gd-local.s b/test/ELF/x86-64-tls-gd-local.s
new file mode 100644 (file)
index 0000000..ec6115d
--- /dev/null
@@ -0,0 +1,52 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s
+
+        .byte   0x66
+        leaq    foo@tlsgd(%rip), %rdi
+        .value  0x6666
+        rex64
+        call    __tls_get_addr@PLT
+
+        .byte   0x66
+        leaq    bar@tlsgd(%rip), %rdi
+        .value  0x6666
+        rex64
+        call    __tls_get_addr@PLT
+
+        .section        .tbss,"awT",@nobits
+
+        .hidden foo
+        .globl  foo
+foo:
+        .zero   4
+
+        .hidden bar
+        .globl  bar
+bar:
+        .zero   4
+
+
+// CHECK:      Name: .got (
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC (0x2)
+// CHECK-NEXT:   SHF_WRITE (0x1)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x30D0
+// CHECK-NEXT: Offset: 0x30D0
+// CHECK-NEXT: Size: 32
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT:   0000: 00000000 00000000 00000000 00000000  |................|
+// CHECK-NEXT:   0010: 00000000 00000000 04000000 00000000  |................|
+// CHECK-NEXT: )
+
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   0x30D0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT:   0x30E0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: }
diff --git a/test/ELF/x86-64-tls-pie.s b/test/ELF/x86-64-tls-pie.s
new file mode 100644 (file)
index 0000000..5ef0f54
--- /dev/null
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-cloudabi %s -o %t1.o
+# RUN: ld.lld -pie %t1.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# Bug 27174: R_X86_64_TPOFF32 and R_X86_64_GOTTPOFF relocations should
+# be eliminated when building a PIE executable, as the static TLS layout
+# is fixed.
+#
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+
+       .globl  _start
+_start:
+       movq    %fs:0, %rax
+       movl    $3, i@TPOFF(%rax)
+
+       movq    %fs:0, %rdx
+       movq    i@GOTTPOFF(%rip), %rcx
+       movl    $3, (%rdx,%rcx)
+
+       .section        .tbss.i,"awT",@nobits
+       .globl  i
+i:
+       .long   0
+       .size   i, 4
diff --git a/test/ELF/zdefs.s b/test/ELF/zdefs.s
new file mode 100644 (file)
index 0000000..93c61e1
--- /dev/null
@@ -0,0 +1,8 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t1.so
+
+# RUN: not ld.lld -z defs -shared %t.o -o %t1.so 2>&1 | FileCheck -check-prefix=ERR %s
+# ERR: error: undefined symbol: foo
+# ERR: >>> referenced by {{.*}}:(.text+0x1)
+
+callq foo@PLT
diff --git a/test/ELF/zstack-size.s b/test/ELF/zstack-size.s
new file mode 100644 (file)
index 0000000..23eed0a
--- /dev/null
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: ld.lld -z stack-size=0x1000 %t -o %t1
+# RUN: llvm-readobj -program-headers %t1 | FileCheck %s -check-prefix=CHECK1
+
+# RUN: ld.lld -z stack-size=0 %t -o %t2
+# RUN: llvm-readobj -program-headers %t2 | FileCheck %s -check-prefix=CHECK2
+
+.global _start
+_start:
+  nop
+
+# CHECK1:     Type: PT_GNU_STACK (0x6474E551)
+# CHECK1-NEXT:     Offset: 0x0
+# CHECK1-NEXT:     VirtualAddress: 0x0
+# CHECK1-NEXT:     PhysicalAddress: 0x0
+# CHECK1-NEXT:     FileSize: 0
+# CHECK1-NEXT:     MemSize: 4096
+# CHECK1-NEXT:     Flags [ (0x6)
+# CHECK1-NEXT:       PF_R (0x4)
+# CHECK1-NEXT:       PF_W (0x2)
+# CHECK1-NEXT:     ]
+
+# CHECK2:     Type: PT_GNU_STACK (0x6474E551)
+# CHECK2-NEXT:     Offset: 0x0
+# CHECK2-NEXT:     VirtualAddress: 0x0
+# CHECK2-NEXT:     PhysicalAddress: 0x0
+# CHECK2-NEXT:     FileSize: 0
+# CHECK2-NEXT:     MemSize: 0
+# CHECK2-NEXT:     Flags [ (0x6)
+# CHECK2-NEXT:       PF_R (0x4)
+# CHECK2-NEXT:       PF_W (0x2)
+# CHECK2-NEXT:     ]
diff --git a/test/ELF/ztext-text-notext.s b/test/ELF/ztext-text-notext.s
new file mode 100644 (file)
index 0000000..964ffe1
--- /dev/null
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/ztext-text-notext.s -o %t2.o
+# RUN: ld.lld %t2.o -o %t2.so -shared
+# RUN: ld.lld -z notext %t.o %t2.so -o %t -shared
+# RUN: llvm-readobj  -dynamic-table -r %t | FileCheck %s
+# RUN: ld.lld -z notext %t.o %t2.so -o %t2 -pie
+# RUN: llvm-readobj  -dynamic-table -r %t2 | FileCheck %s
+# RUN: ld.lld -z notext %t.o %t2.so -o %t3
+# RUN: llvm-readobj  -dynamic-table -r %t3 | FileCheck --check-prefix=STATIC %s
+
+# If the preference is to have text relocations, don't create plt of copy relocations.
+
+# CHECK:      Relocations [
+# CHECK-NEXT:    Section {{.*}} .rela.dyn {
+# CHECK-NEXT:      0x1000 R_X86_64_RELATIVE - 0x1000
+# CHECK-NEXT:      0x1008 R_X86_64_64 bar 0x0
+# CHECK-NEXT:      0x1010 R_X86_64_PC64 zed 0x0
+# CHECK-NEXT:    }
+# CHECK-NEXT:  ]
+# CHECK: DynamicSection [
+# CHECK: 0x0000000000000016 TEXTREL 0x0
+
+# STATIC:      Relocations [
+# STATIC-NEXT:    Section {{.*}} .rela.dyn {
+# STATIC-NEXT:      0x201008 R_X86_64_64 bar 0x0
+# STATIC-NEXT:      0x201010 R_X86_64_PC64 zed 0x0
+# STATIC-NEXT:    }
+# STATIC-NEXT:  ]
+# STATIC: DynamicSection [
+# STATIC: 0x0000000000000016 TEXTREL 0x0
+
+foo:
+.quad foo
+.quad bar
+.quad zed - .
diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg
new file mode 100644 (file)
index 0000000..4bc973a
--- /dev/null
@@ -0,0 +1,23 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import os
+
+import lit.formats
+
+# name: The name of this test suite.
+config.name = 'lld-Unit'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes =  []
+
+# test_source_root: The root path where unit test binaries are located.
+# test_exec_root: The root path where tests should be run.
+config.test_source_root = os.path.join(config.lld_obj_root, 'unittests')
+config.test_exec_root = config.test_source_root
+
+# testFormat: The test format to use to interpret tests.
+if not hasattr(config, 'llvm_build_mode'):
+    lit_config.fatal("unable to find llvm_build_mode value on config")
+config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, 'Tests')
diff --git a/test/Unit/lit.site.cfg.in b/test/Unit/lit.site.cfg.in
new file mode 100644 (file)
index 0000000..c2f3054
--- /dev/null
@@ -0,0 +1,25 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.lld_obj_root = "@LLD_BINARY_DIR@"
+config.lld_src_root = "@LLD_SOURCE_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+    config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+    config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+    config.llvm_build_mode = config.llvm_build_mode % lit_config.params
+except KeyError as e:
+    key, = e.args
+    lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@LLD_SOURCE_DIR@/test/Unit/lit.cfg")
diff --git a/test/darwin/Inputs/native-and-mach-o.objtxt b/test/darwin/Inputs/native-and-mach-o.objtxt
new file mode 100644 (file)
index 0000000..58124eb
--- /dev/null
@@ -0,0 +1,17 @@
+--- !mach-o
+arch:         x86_64
+file-type:    MH_OBJECT
+sections:
+ - segment:     __TEXT
+   section:     __text
+   type:        S_REGULAR
+   attributes:  [ S_ATTR_PURE_INSTRUCTIONS ]
+   address:     0
+   content:     [ 0xC3 ]
+global-symbols:
+ - name:        _foo
+   type:        N_SECT
+   scope:       [ N_EXT ]
+   sect:        1
+   desc:        [ ]
+   value:       0
diff --git a/test/darwin/Inputs/native-and-mach-o2.objtxt b/test/darwin/Inputs/native-and-mach-o2.objtxt
new file mode 100644 (file)
index 0000000..344c9bc
--- /dev/null
@@ -0,0 +1,19 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/darwin/cmdline-objc_gc.objtxt b/test/darwin/cmdline-objc_gc.objtxt
new file mode 100644 (file)
index 0000000..b5225a1
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: not lld -flavor darwin -arch x86_64 -objc_gc %s 2>&1 | FileCheck %s
+#
+# Test that the -objc_gc is rejected.
+#
+
+# CHECK: error: -objc_gc is not supported
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 0x90 ]
+
+...
diff --git a/test/darwin/cmdline-objc_gc_compaction.objtxt b/test/darwin/cmdline-objc_gc_compaction.objtxt
new file mode 100644 (file)
index 0000000..acf7183
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_compaction %s 2>&1 | FileCheck %s
+#
+# Test that the -objc_gc_compaction is rejected.
+#
+
+# CHECK: error: -objc_gc_compaction is not supported
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 0x90 ]
+
+...
diff --git a/test/darwin/cmdline-objc_gc_only.objtxt b/test/darwin/cmdline-objc_gc_only.objtxt
new file mode 100644 (file)
index 0000000..db1cef9
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_only %s 2>&1 | FileCheck %s
+#
+# Test that the -objc_gc_only is rejected.
+#
+
+# CHECK: error: -objc_gc_only is not supported
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 0x90 ]
+
+...
diff --git a/test/darwin/native-and-mach-o.objtxt b/test/darwin/native-and-mach-o.objtxt
new file mode 100644 (file)
index 0000000..1dee76d
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/native-and-mach-o.objtxt  \
+# RUN: %p/Inputs/native-and-mach-o2.objtxt -o %t  && \
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test a mix of atoms and mach-o both encoded in yaml
+#
+
+--- !native
+defined-atoms:
+    - name:              _main
+      type:              code
+      scope:             global
+      content:           [ 55, 48, 89, E5, 30, C0, E8, 00,
+                           00, 00, 00, 31, C0, 5D, C3 ]
+      references:
+      - offset:          7
+        kind:            branch32
+        target:          _foo
+
+undefined-atoms:
+ - name:                _foo
+
+...
+
+# CHECK:       {{[0-9a-f]+}} T _foo
+# CHECK:       {{[0-9a-f]+}} T _main
diff --git a/test/lit.cfg b/test/lit.cfg
new file mode 100644 (file)
index 0000000..95bf3c0
--- /dev/null
@@ -0,0 +1,270 @@
+# -*- Python -*-
+
+import os
+import platform
+import re
+import subprocess
+import locale
+
+import lit.formats
+import lit.util
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'lld'
+
+# Tweak PATH for Win32
+if sys.platform in ['win32']:
+    # Seek sane tools in directories and set to $PATH.
+    path = getattr(config, 'lit_tools_dir', None)
+    path = lit_config.getToolsPath(path,
+                                   config.environment['PATH'],
+                                   ['cmp.exe', 'grep.exe', 'sed.exe'])
+    if path is not None:
+        path = os.path.pathsep.join((path,
+                                     config.environment['PATH']))
+        config.environment['PATH'] = path
+
+# Choose between lit's internal shell pipeline runner and a real shell.  If
+# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
+use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
+if use_lit_shell:
+    # 0 is external, "" is default, and everything else is internal.
+    execute_external = (use_lit_shell == "0")
+else:
+    # Otherwise we default to internal on Windows and external elsewhere, as
+    # bash on Windows is usually very slow.
+    execute_external = (not sys.platform in ['win32'])
+
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+config.test_format = lit.formats.ShTest(execute_external)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.ll', '.s', '.test', '.yaml', '.objtxt']
+
+# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
+# subdirectories contain auxiliary inputs for various tests in their parent
+# directories.
+config.excludes = ['Inputs']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+lld_obj_root = getattr(config, 'lld_obj_root', None)
+if lld_obj_root is not None:
+    config.test_exec_root = os.path.join(lld_obj_root, 'test')
+
+# Set llvm_{src,obj}_root for use by others.
+config.llvm_src_root = getattr(config, 'llvm_src_root', None)
+config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
+
+# Tweak the PATH to include the tools dir and the scripts dir.
+if lld_obj_root is not None:
+    lld_tools_dir = getattr(config, 'lld_tools_dir', None)
+    if not lld_tools_dir:
+        lit_config.fatal('No LLD tools dir set!')
+    llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+    if not llvm_tools_dir:
+        lit_config.fatal('No LLVM tools dir set!')
+    path = os.path.pathsep.join((lld_tools_dir, llvm_tools_dir, config.environment['PATH']))
+    path = os.path.pathsep.join((os.path.join(getattr(config, 'llvm_src_root', None),'test','Scripts'),path))
+
+    config.environment['PATH'] = path
+
+    lld_libs_dir = getattr(config, 'lld_libs_dir', None)
+    if not lld_libs_dir:
+        lit_config.fatal('No LLD libs dir set!')
+    llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
+    if not llvm_libs_dir:
+        lit_config.fatal('No LLVM libs dir set!')
+    path = os.path.pathsep.join((lld_libs_dir, llvm_libs_dir,
+                                 config.environment.get('LD_LIBRARY_PATH','')))
+    config.environment['LD_LIBRARY_PATH'] = path
+
+    # Propagate LLVM_SRC_ROOT into the environment.
+    config.environment['LLVM_SRC_ROOT'] = getattr(config, 'llvm_src_root', '')
+
+    # Propagate PYTHON_EXECUTABLE into the environment
+    config.environment['PYTHON_EXECUTABLE'] = getattr(config, 'python_executable',
+                                                      '')
+###
+
+# Check that the object root is known.
+if config.test_exec_root is None:
+    # Otherwise, we haven't loaded the site specific configuration (the user is
+    # probably trying to run on a test file directly, and either the site
+    # configuration hasn't been created by the build system, or we are in an
+    # out-of-tree build situation).
+
+    # Check for 'lld_site_config' user parameter, and use that if available.
+    site_cfg = lit_config.params.get('lld_site_config', None)
+    if site_cfg and os.path.exists(site_cfg):
+        lit_config.load_config(config, site_cfg)
+        raise SystemExit
+
+    # Try to detect the situation where we are using an out-of-tree build by
+    # looking for 'llvm-config'.
+    #
+    # FIXME: I debated (i.e., wrote and threw away) adding logic to
+    # automagically generate the lit.site.cfg if we are in some kind of fresh
+    # build situation. This means knowing how to invoke the build system though,
+    # and I decided it was too much magic. We should solve this by just having
+    # the .cfg files generated during the configuration step.
+
+    llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
+    if not llvm_config:
+        lit_config.fatal('No site specific configuration available!')
+
+    # Get the source and object roots.
+    llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip()
+    llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip()
+    lld_src_root = os.path.join(llvm_src_root, "tools", "lld")
+    lld_obj_root = os.path.join(llvm_obj_root, "tools", "lld")
+
+    # Validate that we got a tree which points to here, using the standard
+    # tools/lld layout.
+    this_src_root = os.path.dirname(config.test_source_root)
+    if os.path.realpath(lld_src_root) != os.path.realpath(this_src_root):
+        lit_config.fatal('No site specific configuration available!')
+
+    # Check that the site specific configuration exists.
+    site_cfg = os.path.join(lld_obj_root, 'test', 'lit.site.cfg')
+    if not os.path.exists(site_cfg):
+        lit_config.fatal(
+            'No site specific configuration available! You may need to '
+            'run "make test" in your lld build directory.')
+
+    # Okay, that worked. Notify the user of the automagic, and reconfigure.
+    lit_config.note('using out-of-tree build at %r' % lld_obj_root)
+    lit_config.load_config(config, site_cfg)
+    raise SystemExit
+
+# For each occurrence of a lld tool name as its own word, replace it
+# with the full path to the build directory holding that tool.  This
+# ensures that we are testing the tools just built and not some random
+# tools that might happen to be in the user's PATH.
+
+# Regex assertions to reject neighbor hyphens/dots (seen in some tests).
+# For example, we want to prefix 'lld' and 'ld.lld' but not the 'lld' inside
+# of 'ld.lld'.
+NoPreJunk = r"(?<!(-|\.|/))"
+NoPostJunk = r"(?!(-|\.))"
+
+config.substitutions.append( (r"\bld.lld\b", 'ld.lld --full-shutdown') )
+
+tool_patterns = [r"\bFileCheck\b",
+                 r"\bnot\b",
+                 NoPreJunk + r"\blld\b" + NoPostJunk,
+                 r"\bld.lld\b",
+                 r"\blld-link\b",
+                 r"\bllvm-as\b",
+                 r"\bllvm-mc\b",
+                 r"\bllvm-nm\b",
+                 r"\bllvm-objdump\b",
+                 r"\bllvm-pdbutil\b",
+                 r"\bllvm-readobj\b",
+                 r"\bobj2yaml\b",
+                 r"\byaml2obj\b"]
+
+for pattern in tool_patterns:
+    # Extract the tool name from the pattern.  This relies on the tool
+    # name being surrounded by \b word match operators.  If the
+    # pattern starts with "| ", include it in the string to be
+    # substituted.
+    tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_\.]+)\\b\W*$",
+                          pattern)
+    tool_pipe = tool_match.group(2)
+    tool_name = tool_match.group(4)
+    tool_path = lit.util.which(tool_name, config.environment['PATH'])
+    if not tool_path:
+        # Warn, but still provide a substitution.
+        lit_config.note('Did not find ' + tool_name + ' in ' + path)
+        tool_path = llvm_tools_dir + '/' + tool_name
+    config.substitutions.append((pattern, tool_pipe + tool_path))
+
+# Add site-specific substitutions.
+config.substitutions.append( ('%python', config.python_executable) )
+
+###
+
+# When running under valgrind, we mangle '-vg' onto the end of the triple so we
+# can check it with XFAIL and XTARGET.
+if lit_config.useValgrind:
+    config.target_triple += '-vg'
+
+# Shell execution
+if execute_external:
+    config.available_features.add('shell')
+
+# zlib compression library
+if config.have_zlib:
+    config.available_features.add("zlib")
+
+# Running on Darwin OS
+if platform.system() in ['Darwin']:
+    config.available_features.add('system-linker-mach-o')
+
+# Running on ELF based *nix
+if platform.system() in ['FreeBSD', 'Linux']:
+    config.available_features.add('system-linker-elf')
+
+# Running on Windows
+if platform.system() in ['Windows']:
+    config.available_features.add('system-windows')
+
+# Set if host-cxxabi's demangler can handle target's symbols.
+if platform.system() not in ['Windows']:
+    config.available_features.add('demangler')
+
+# llvm-config knows whether it is compiled with asserts (and)
+# whether we are operating in release/debug mode.
+import subprocess
+try:
+    llvm_config_cmd = \
+     subprocess.Popen([os.path.join(llvm_tools_dir, 'llvm-config'),
+                     '--build-mode', '--assertion-mode', '--targets-built'],
+                      stdout = subprocess.PIPE)
+except OSError as why:
+    print("Could not find llvm-config in " + llvm_tools_dir)
+    exit(42)
+
+llvm_config_output = llvm_config_cmd.stdout.read().decode('utf_8')
+llvm_config_output_list = llvm_config_output.split("\n")
+
+if re.search(r'DEBUG', llvm_config_output_list[0]):
+    config.available_features.add('debug')
+if re.search(r'ON', llvm_config_output_list[1]):
+    config.available_features.add('asserts')
+
+archs = llvm_config_output_list[2]
+if re.search(r'AArch64', archs):
+    config.available_features.add('aarch64')
+if re.search(r'AMDGPU', archs):
+    config.available_features.add('amdgpu')
+if re.search(r'ARM', archs):
+    config.available_features.add('arm')
+if re.search(r'AVR', archs):
+    config.available_features.add('avr')
+if re.search(r'Mips', archs):
+    config.available_features.add('mips')
+if re.search(r'PowerPC', archs):
+    config.available_features.add('ppc')
+if re.search(r'Sparc', archs):
+    config.available_features.add('sparc')
+if re.search(r'X86', archs):
+    config.available_features.add('x86')
+llvm_config_cmd.wait()
+
+# Set a fake constant version so that we get consitent output.
+config.environment['LLD_VERSION'] = 'LLD 1.0'
+
+# Indirectly check if the mt.exe Microsoft utility exists by searching for
+# cvtres, which always accompanies it.
+if lit.util.which('cvtres', config.environment['PATH']):
+    config.available_features.add('win_mt')
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
new file mode 100644 (file)
index 0000000..1fb8d36
--- /dev/null
@@ -0,0 +1,25 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.lld_obj_root = "@LLD_BINARY_DIR@"
+config.lld_libs_dir = "@LLVM_LIBRARY_OUTPUT_INTDIR@"
+config.lld_tools_dir = "@LLVM_RUNTIME_OUTPUT_INTDIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+config.have_zlib = @HAVE_LIBZ@
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+    config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+    config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+except KeyError as e:
+    key, = e.args
+    lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@LLD_SOURCE_DIR@/test/lit.cfg")
diff --git a/test/mach-o/Inputs/DependencyDump.py b/test/mach-o/Inputs/DependencyDump.py
new file mode 100755 (executable)
index 0000000..0f4d49d
--- /dev/null
@@ -0,0 +1,30 @@
+# -*- Python -*-
+
+
+#
+# Dump out Xcode binary dependency file.
+#
+
+import sys
+
+f = open(sys.argv[1], "rb")
+byte = f.read(1)
+while byte != b'':
+    if byte == b'\000':
+        sys.stdout.write("linker-vers: ")
+    elif byte == b'\020':
+        sys.stdout.write("input-file:  ")
+    elif byte == b'\021':
+        sys.stdout.write("not-found:   ")
+    elif byte == b'\100':
+        sys.stdout.write("output-file: ")
+    byte = f.read(1)
+    while byte != b'\000':
+        if byte != b'\012':
+            sys.stdout.write(byte.decode("ascii"))
+        byte = f.read(1)
+    sys.stdout.write("\n")
+    byte = f.read(1)
+
+f.close()
+
diff --git a/test/mach-o/Inputs/PIE.yaml b/test/mach-o/Inputs/PIE.yaml
new file mode 100644 (file)
index 0000000..0463154
--- /dev/null
@@ -0,0 +1,6 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/arm-interworking.yaml b/test/mach-o/Inputs/arm-interworking.yaml
new file mode 100644 (file)
index 0000000..d78a299
--- /dev/null
@@ -0,0 +1,83 @@
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFE, 0xFF, 0xFF, 0xEB, 0x02, 0x00, 0x00, 0xFA,
+                       0xFC, 0xFF, 0xFF, 0xEB, 0xFB, 0xFF, 0xFF, 0xFA,
+                       0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1 ]
+    relocations:
+      - offset:          0x0000000C
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000004
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000018
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000004
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+local-symbols:
+  - name:            _d2
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000018
+global-symbols:
+  - name:            _a1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _a2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000014
+undefined-symbols:
+  - name:            _t1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/arm-shims.yaml b/test/mach-o/Inputs/arm-shims.yaml
new file mode 100644 (file)
index 0000000..8baebef
--- /dev/null
@@ -0,0 +1,60 @@
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
+                       0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
+                       0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
+    relocations:
+      - offset:          0x00000014
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000010
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000006
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000002
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _a2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            _t2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _a1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _t1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/arm64/libSystem.yaml b/test/mach-o/Inputs/arm64/libSystem.yaml
new file mode 100644 (file)
index 0000000..76cba1b
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# For use by test cases that create dynamic output types which may needs stubs
+# and therefore will need a dylib definition of dyld_stub_binder.
+#
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
+
+...
diff --git a/test/mach-o/Inputs/armv7/libSystem.yaml b/test/mach-o/Inputs/armv7/libSystem.yaml
new file mode 100644 (file)
index 0000000..2539f90
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# For use by test cases that create dynamic output types which may needs stubs
+# and therefore will need a dylib definition of dyld_stub_binder.
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
+
+...
diff --git a/test/mach-o/Inputs/bar.yaml b/test/mach-o/Inputs/bar.yaml
new file mode 100644 (file)
index 0000000..5605e67
--- /dev/null
@@ -0,0 +1,18 @@
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/cstring-sections.yaml b/test/mach-o/Inputs/cstring-sections.yaml
new file mode 100644 (file)
index 0000000..eb227f2
--- /dev/null
@@ -0,0 +1,25 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __objc_methname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x61, 0x62, 0x63, 0x00 ]
+  - segment:         __TEXT
+    section:         __objc_classname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000006
+    content:         [ 0x61, 0x62, 0x63, 0x00 ]
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x000000000000000A
+    content:         [ 0x61, 0x62, 0x63, 0x00 ]
diff --git a/test/mach-o/Inputs/exported_symbols_list.exp b/test/mach-o/Inputs/exported_symbols_list.exp
new file mode 100644 (file)
index 0000000..ff66533
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# For use with exported_symbols_list.yaml
+#
+_foo
+_b
+
diff --git a/test/mach-o/Inputs/full.filelist b/test/mach-o/Inputs/full.filelist
new file mode 100644 (file)
index 0000000..abf98b6
--- /dev/null
@@ -0,0 +1,3 @@
+/foo/bar/a.o
+/foo/bar/b.o
+/foo/x.a
diff --git a/test/mach-o/Inputs/got-order.yaml b/test/mach-o/Inputs/got-order.yaml
new file mode 100644 (file)
index 0000000..d256e9d
--- /dev/null
@@ -0,0 +1,53 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x0D, 0x00,
+                       0x00, 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x8B, 0x00, 0x03, 0x01, 0x48, 0x8B,
+                       0x0D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000019
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000000E
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000007
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _zazzle
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/got-order2.yaml b/test/mach-o/Inputs/got-order2.yaml
new file mode 100644 (file)
index 0000000..faddeda
--- /dev/null
@@ -0,0 +1,11 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libfoobar.dylib
+exports:
+  - name:            _bar
+  - name:            _zazzle
+  - name:            _foo
+  - name:            _aaa
+  - name:            _fff
+  - name:            _zzz
diff --git a/test/mach-o/Inputs/hello-world-arm64.yaml b/test/mach-o/Inputs/hello-world-arm64.yaml
new file mode 100644 (file)
index 0000000..31de71e
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:            arm64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _fprintf
+  - name:            ___stdoutp
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-armv6.yaml b/test/mach-o/Inputs/hello-world-armv6.yaml
new file mode 100644 (file)
index 0000000..0b29f65
--- /dev/null
@@ -0,0 +1,7 @@
+--- !mach-o
+arch:            armv6
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _printf
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-armv7.yaml b/test/mach-o/Inputs/hello-world-armv7.yaml
new file mode 100644 (file)
index 0000000..4e26120
--- /dev/null
@@ -0,0 +1,7 @@
+--- !mach-o
+arch:            armv7
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _printf
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-x86.yaml b/test/mach-o/Inputs/hello-world-x86.yaml
new file mode 100644 (file)
index 0000000..dbec62b
--- /dev/null
@@ -0,0 +1,7 @@
+--- !mach-o
+arch:            x86
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _printf
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/hello-world-x86_64.yaml b/test/mach-o/Inputs/hello-world-x86_64.yaml
new file mode 100644 (file)
index 0000000..7840d5c
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _fprintf
+  - name:            dyld_stub_binder
+  - name:            ___stdoutp
diff --git a/test/mach-o/Inputs/hw.raw_bytes b/test/mach-o/Inputs/hw.raw_bytes
new file mode 100644 (file)
index 0000000..ce01362
--- /dev/null
@@ -0,0 +1 @@
+hello
diff --git a/test/mach-o/Inputs/interposing-section.yaml b/test/mach-o/Inputs/interposing-section.yaml
new file mode 100644 (file)
index 0000000..45966b6
--- /dev/null
@@ -0,0 +1,6 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            _open
diff --git a/test/mach-o/Inputs/lazy-bind-x86_64-2.yaml b/test/mach-o/Inputs/lazy-bind-x86_64-2.yaml
new file mode 100644 (file)
index 0000000..50a97bc
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libfoo.dylib
+compat-version:    2.0
+current-version:   3.4
+exports:
+  - name:            _foo
diff --git a/test/mach-o/Inputs/lazy-bind-x86_64-3.yaml b/test/mach-o/Inputs/lazy-bind-x86_64-3.yaml
new file mode 100644 (file)
index 0000000..2f61cc0
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libbaz.dylib
+compat-version:    3.0
+current-version:   4.5
+exports:
+  - name:            _baz
diff --git a/test/mach-o/Inputs/lazy-bind-x86_64.yaml b/test/mach-o/Inputs/lazy-bind-x86_64.yaml
new file mode 100644 (file)
index 0000000..7e6cd90
--- /dev/null
@@ -0,0 +1,8 @@
+--- !mach-o
+arch:              x86_64
+file-type:         MH_DYLIB
+install-name:      /usr/lib/libbar.dylib
+compat-version:    1.0
+current-version:   2.3
+exports:
+  - name:            _bar
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib
new file mode 100755 (executable)
index 0000000..71185fb
Binary files /dev/null and b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib differ
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a
new file mode 100644 (file)
index 0000000..b120629
Binary files /dev/null and b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a differ
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o b/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o
new file mode 100644 (file)
index 0000000..f9a923d
Binary files /dev/null and b/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o differ
diff --git a/test/mach-o/Inputs/libbar.a b/test/mach-o/Inputs/libbar.a
new file mode 100644 (file)
index 0000000..64cae6c
Binary files /dev/null and b/test/mach-o/Inputs/libbar.a differ
diff --git a/test/mach-o/Inputs/libfoo.a b/test/mach-o/Inputs/libfoo.a
new file mode 100644 (file)
index 0000000..21194ef
Binary files /dev/null and b/test/mach-o/Inputs/libfoo.a differ
diff --git a/test/mach-o/Inputs/linker-as-ld.yaml b/test/mach-o/Inputs/linker-as-ld.yaml
new file mode 100644 (file)
index 0000000..0463154
--- /dev/null
@@ -0,0 +1,6 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
diff --git a/test/mach-o/Inputs/no-version-min-load-command-object.yaml b/test/mach-o/Inputs/no-version-min-load-command-object.yaml
new file mode 100644 (file)
index 0000000..35f83c6
--- /dev/null
@@ -0,0 +1,22 @@
+
+# This object file has no version min and so will prevent any -r link from emitting
+# a version min.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
diff --git a/test/mach-o/Inputs/order_file-basic.order b/test/mach-o/Inputs/order_file-basic.order
new file mode 100644 (file)
index 0000000..0ac90cb
--- /dev/null
@@ -0,0 +1,11 @@
+
+# input file for order_file-basic.yaml
+
+_func2
+libfoo.a(foo.o):_foo  # tests file specific ordering within archive
+i386:_func3           # wrong arch, so ignored
+armv7:_func3          # wrong arch, so ignored
+_func1
+_notfound             # unknown symbol silently ignored
+_data3                # data symbols should be orderable
+
diff --git a/test/mach-o/Inputs/partial.filelist b/test/mach-o/Inputs/partial.filelist
new file mode 100644 (file)
index 0000000..281581b
--- /dev/null
@@ -0,0 +1,3 @@
+bar/a.o
+bar/b.o
+x.a
diff --git a/test/mach-o/Inputs/re-exported-dylib-ordinal.yaml b/test/mach-o/Inputs/re-exported-dylib-ordinal.yaml
new file mode 100644 (file)
index 0000000..1941b40
--- /dev/null
@@ -0,0 +1,21 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /junk/libfoo.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000F9A
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000F9A
+dependents:
+  - path:            /junk/libbar.dylib
+    kind:            LC_REEXPORT_DYLIB
diff --git a/test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml b/test/mach-o/Inputs/re-exported-dylib-ordinal2.yaml
new file mode 100644 (file)
index 0000000..5aaf8c1
--- /dev/null
@@ -0,0 +1,18 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /junk/libbar.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000F9A
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000F9A
diff --git a/test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml b/test/mach-o/Inputs/re-exported-dylib-ordinal3.yaml
new file mode 100644 (file)
index 0000000..43ba07c
--- /dev/null
@@ -0,0 +1,19 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_TWOLEVEL ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/swift-version-1.yaml b/test/mach-o/Inputs/swift-version-1.yaml
new file mode 100644 (file)
index 0000000..1337d7a
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/hello-world-x86_64.yaml 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 ]
+...
diff --git a/test/mach-o/Inputs/unwind-info-simple-arm64.yaml b/test/mach-o/Inputs/unwind-info-simple-arm64.yaml
new file mode 100644 (file)
index 0000000..5f7ae50
--- /dev/null
@@ -0,0 +1,13 @@
+--- !mach-o
+arch:            arm64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libc++.dylib
+exports:
+  - name:            __Unwind_Resume
+  - name:            __ZTIl
+  - name:            __ZTIi
+  - name:            ___cxa_end_catch
+  - name:            ___cxa_begin_catch
+  - name:            ___cxa_allocate_exception
+  - name:            ___cxa_throw
+  - name:            ___gxx_personality_v0
diff --git a/test/mach-o/Inputs/use-dylib-install-names.yaml b/test/mach-o/Inputs/use-dylib-install-names.yaml
new file mode 100644 (file)
index 0000000..cec2559
--- /dev/null
@@ -0,0 +1,28 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00,
+                       0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00,
+                       0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _myGlobal
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/use-simple-dylib.yaml b/test/mach-o/Inputs/use-simple-dylib.yaml
new file mode 100644 (file)
index 0000000..9081bcf
--- /dev/null
@@ -0,0 +1,58 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+  - name:            _myVariablePreviouslyKnownAsPrivateExtern
+    type:            N_SECT
+    scope:           [ N_PEXT ]
+    sect:            1
+    desc:            [ N_SYMBOL_RESOLVER ]
+    value:           0x0000000000000011
+global-symbols:
+  - name:            _myGlobal
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000002
+  - name:            _myHidden
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _myHiddenWeak
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000007
+  - name:            _myResolver
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_SYMBOL_RESOLVER ]
+    value:           0x0000000000000010
+
+install-name:        libspecial.dylib
diff --git a/test/mach-o/Inputs/write-final-sections.yaml b/test/mach-o/Inputs/write-final-sections.yaml
new file mode 100644 (file)
index 0000000..ed43491
--- /dev/null
@@ -0,0 +1,20 @@
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
diff --git a/test/mach-o/Inputs/wrong-arch-error.yaml b/test/mach-o/Inputs/wrong-arch-error.yaml
new file mode 100644 (file)
index 0000000..304c872
--- /dev/null
@@ -0,0 +1,24 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
diff --git a/test/mach-o/Inputs/x86/libSystem.yaml b/test/mach-o/Inputs/x86/libSystem.yaml
new file mode 100644 (file)
index 0000000..87a4895
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# For use by test cases that create dynamic output types which may needs stubs
+# and therefore will need a dylib definition of dyld_stub_binder.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
+
+...
diff --git a/test/mach-o/Inputs/x86_64/libSystem.yaml b/test/mach-o/Inputs/x86_64/libSystem.yaml
new file mode 100644 (file)
index 0000000..fbbf794
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# For use by test cases that create dynamic output types which may needs stubs
+# and therefore will need a dylib definition of dyld_stub_binder.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+install-name:    /usr/lib/libSystem.B.dylib
+exports:
+  - name:            dyld_stub_binder
+
+...
diff --git a/test/mach-o/PIE.yaml b/test/mach-o/PIE.yaml
new file mode 100644 (file)
index 0000000..24f8773
--- /dev/null
@@ -0,0 +1,40 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/PIE.yaml -o %t  && \
+# RUN: llvm-objdump -macho -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/PIE.yaml -pie -o %t\
+# RUN:  &&  llvm-objdump -macho -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/PIE.yaml -no_pie -o %t\
+# RUN:  &&  llvm-objdump -macho -private-headers %t \
+# RUN:  | FileCheck --check-prefix=CHECK_NO_PIE %s
+#
+# Test various PIE options.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+# CHECK:                 MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE
+# CHECK_NO_PIE-NOT:    MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE
diff --git a/test/mach-o/align_text.yaml b/test/mach-o/align_text.yaml
new file mode 100644 (file)
index 0000000..66b5afb
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -r %t -o %t2 -print_atoms | FileCheck %s
+#
+# Test that alignment info round trips through -r
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x90, 0x90, 0x90, 0xC3, 0xC3, 0xC3 ]
+local-symbols:
+  - name:            _f1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000003
+  - name:            _f2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _f3
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000005
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - content:         [ 90, 90, 90 ]
+# CHECK:     alignment:       16
+# CHECK:   - name:            _f1
+# CHECK:     content:         [ C3 ]
+# CHECK:     alignment:       3 mod 16
+# CHECK:   - name:            _f2
+# CHECK:     content:         [ C3 ]
+# CHECK:     alignment:       4 mod 16
+# CHECK:   - name:            _f3
+# CHECK:     content:         [ C3 ]
+# CHECK:     alignment:       5 mod 16
diff --git a/test/mach-o/arm-interworking-movw.yaml b/test/mach-o/arm-interworking-movw.yaml
new file mode 100644 (file)
index 0000000..b555112
--- /dev/null
@@ -0,0 +1,393 @@
+# REQUIRES: arm
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t  | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -dylib -print_atoms %t -o %t2 \
+# RUN:     %p/Inputs/armv7/libSystem.yaml -sectalign __TEXT __text 0x1000  | FileCheck %s
+# RUN: llvm-objdump -d -macho -no-symbolic-operands %t2 | FileCheck -check-prefix=CODE %s
+#
+# Test thumb and arm branches round trip through -r.
+# Test movw/movt pairs have low bit set properly for thumb vs arm.
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x40, 0xF2, 0x25, 0x00, 0xC0, 0xF2, 0x00, 0x00,
+                       0x40, 0xF2, 0x01, 0x01, 0xC0, 0xF2, 0x00, 0x01,
+                       0x40, 0xF2, 0x4E, 0x02, 0xC0, 0xF2, 0x00, 0x02,
+                       0x40, 0xF2, 0x2A, 0x03, 0xC0, 0xF2, 0x00, 0x03,
+                       0x78, 0x44, 0x70, 0x47, 0x70, 0x47, 0x25, 0x00,
+                       0x00, 0xE3, 0x00, 0x00, 0x40, 0xE3, 0xD7, 0x1F,
+                       0x0F, 0xE3, 0xFF, 0x1F, 0x4F, 0xE3, 0x4E, 0x20,
+                       0x00, 0xE3, 0x00, 0x20, 0x40, 0xE3, 0x00, 0x30,
+                       0x00, 0xE3, 0x00, 0x30, 0x40, 0xE3, 0x0F, 0x00,
+                       0x80, 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF,
+                       0x2F, 0xE1 ]
+    relocations:
+      - offset:          0x00000042
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000003E
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000003A
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x0000004E
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000036
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000032
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x0000FFD6
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000002E
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x0000FFFF
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000046
+      - offset:          0x0000002A
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000025
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000026
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x0000002A
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000018
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000004E
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000014
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x0000004E
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000010
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000000C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000008
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000024
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000004
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000025
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000000
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+local-symbols:
+  - name:            _t1
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000024
+  - name:            _a2
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000004E
+  - name:            _a1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000026
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _t1
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_movw
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movt
+# CHECK:         offset:          4
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movw_funcRel
+# CHECK:         offset:          8
+# CHECK:         target:          _t2
+# CHECK:         addend:          -36
+# CHECK:       - kind:            thumb_movt_funcRel
+# CHECK:         offset:          12
+# CHECK:         target:          _t2
+# CHECK:         addend:          -36
+# CHECK:       - kind:            thumb_movw
+# CHECK:         offset:          16
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movt
+# CHECK:         offset:          20
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            thumb_movw_funcRel
+# CHECK:         offset:          24
+# CHECK:         target:          _a2
+# CHECK:         addend:          -36
+# CHECK:       - kind:            thumb_movt_funcRel
+# CHECK:         offset:          28
+# CHECK:         target:          _a2
+# CHECK:         addend:          -36
+# CHECK:   - name:            _t2
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK:   - name:            _a1
+# CHECK:     references:
+# CHECK:       - kind:            arm_movw
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movt
+# CHECK:         offset:          4
+# CHECK:         target:          _t2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movw_funcRel
+# CHECK:         offset:          8
+# CHECK:         target:          _t2
+# CHECK:         addend:          -40
+# CHECK:       - kind:            arm_movt_funcRel
+# CHECK:         offset:          12
+# CHECK:         target:          _t2
+# CHECK:         addend:          -40
+# CHECK:       - kind:            arm_movw
+# CHECK:         offset:          16
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movt
+# CHECK:         offset:          20
+# CHECK:         target:          _a2
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            arm_movw_funcRel
+# CHECK:         offset:          24
+# CHECK:         target:          _a2
+# CHECK:         addend:          -40
+# CHECK:       - kind:            arm_movt_funcRel
+# CHECK:         offset:          28
+# CHECK:         target:          _a2
+# CHECK:         addend:          -40
+# CHECK:   - name:            _a2
+
+
+# CODE: _t1:
+# CODE-NEXT:                    movw   r0, #4133
+# CODE-NEXT:                   movt    r0, #0
+# CODE-NEXT:                   movw    r1, #1
+# CODE-NEXT:                   movt    r1, #0
+# CODE-NEXT:                   movw    r2, #4174
+# CODE-NEXT:                   movt    r2, #0
+# CODE-NEXT:                   movw    r3, #42
+# CODE-NEXT:                   movt    r3, #0
+
+
+# CODE: _a1:
+# CODE-NEXT:                    movw   r0, #4133
+# CODE-NEXT:                   movt    r0, #0
+# CODE-NEXT:                   movw    r1, #65495
+# CODE-NEXT:                   movt    r1, #65535
+# CODE-NEXT:                   movw    r2, #4174
+# CODE-NEXT:                   movt    r2, #0
+# CODE-NEXT:                   movw    r3, #0
+# CODE-NEXT:                   movt    r3, #0
+
+
+
+#      .syntax unified
+#      .align  2
+#
+#      .code   16
+#  .thumb_func _t1
+#_t1:
+#      movw    r0, :lower16:(_t2)
+#      movt    r0, :upper16:(_t2)
+#      movw    r1, :lower16:(_t2-(L0+4))
+#      movt    r1, :upper16:(_t2-(L0+4))
+#      movw    r2, :lower16:(_a2)
+#      movt    r2, :upper16:(_a2)
+#      movw    r3, :lower16:(_a2-(L0+4))
+#      movt    r3, :upper16:(_a2-(L0+4))
+#L0:
+#      add     r0, pc
+#      bx      lr
+#
+#
+#      .code   16
+#      .thumb_func     _t2
+#_t2:
+#      bx      lr
+#
+#
+#
+#      .code   32
+#_a1:
+#      movw    r0, :lower16:(_t2)
+#      movt    r0, :upper16:(_t2)
+#      movw    r1, :lower16:(_t2-(L1+8))
+#      movt    r1, :upper16:(_t2-(L1+8))
+#      movw    r2, :lower16:(_a2)
+#      movt    r2, :upper16:(_a2)
+#      movw    r3, :lower16:(_a2-(L1+8))
+#      movt    r3, :upper16:(_a2-(L1+8))
+#L1:
+#      add     r0, pc
+#      bx      lr
+#
+#_a2:
+#      bx      lr
+
diff --git a/test/mach-o/arm-interworking.yaml b/test/mach-o/arm-interworking.yaml
new file mode 100644 (file)
index 0000000..3988a19
--- /dev/null
@@ -0,0 +1,288 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s \
+# RUN: %p/Inputs/arm-interworking.yaml -o %t  | FileCheck %s \
+# RUN: && lld -flavor darwin -arch armv7 -dylib -print_atoms \
+# RUN:         %p/Inputs/armv7/libSystem.yaml %t -o %t2  | FileCheck %s \
+# RUN: && llvm-readobj -s -sd %t2 | FileCheck -check-prefix=CODE %s
+#
+# Test thumb and arm branches round trip through -r.
+# Test bl/blx instructions are fixed up properly.
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFF, 0xF7, 0xFE, 0xFF, 0xC0, 0x46, 0xFF, 0xF7,
+                       0xFC, 0xEF, 0xC0, 0x46, 0xFF, 0xF7, 0xF8, 0xEF,
+                       0xFF, 0xF7, 0xF6, 0xFF, 0xC0, 0x46, 0xFF, 0xF7,
+                       0xF3, 0xFF, 0xC0, 0x46, 0x00, 0xF0, 0x06, 0xE8,
+                       0xC0, 0x46, 0x00, 0xF0, 0x03, 0xF8, 0x00, 0xF0,
+                       0x02, 0xF8, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47 ]
+    relocations:
+      - offset:          0x00000026
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000022
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x0000001C
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000016
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000010
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x0000000C
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000006
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000000
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000030
+    content:         [ 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000004
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+local-symbols:
+  - name:            _t3
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x000000000000002E
+  - name:            _d1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000030
+global-symbols:
+  - name:            _t1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x000000000000002C
+undefined-symbols:
+  - name:            _a1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _a2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _d1
+# CHECK:     type:            data
+# CHECK:     references:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          4
+# CHECK:         target:          _a1
+# CHECK:   - name:            _d2
+# CHECK:     type:            data
+# CHECK:     references:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          0
+# CHECK:         target:          _t1
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          4
+# CHECK:         target:          _a1
+# CHECK:   - name:            _t1
+# CHECK:     scope:           global
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          0
+# CHECK:         target:          _a1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          6
+# CHECK:         target:          _a2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          12
+# CHECK:         target:          _a2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          16
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          22
+# CHECK:         target:          _t1
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          28
+# CHECK:         target:          _t2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          34
+# CHECK:         target:          _t2
+# CHECK:       - kind:            thumb_bl22
+# CHECK:         offset:          38
+# CHECK:         target:          _t3
+# CHECK:   - name:            _t2
+# CHECK:     scope:           global
+# CHECK:     content:         [ 70, 47 ]
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t2
+# CHECK:   - name:            _t3
+# CHECK:     content:         [ 70, 47 ]
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:         target:          _t3
+# CHECK:   - name:            _a1
+# CHECK:     scope:           global
+# CHECK:     references:
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          0
+# CHECK:         target:          _a1
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          4
+# CHECK:         target:          _a2
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          8
+# CHECK:         target:          _t1
+# CHECK:       - kind:            arm_bl24
+# CHECK:         offset:          12
+# CHECK:         target:          _t2
+# CHECK:   - name:            _a2
+# CHECK:     scope:           global
+
+# CODE:     Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CODE:     Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CODE:     SectionData (
+# CODE:       0000: 00F016E8 C04600F0 1EE8C046 00F01AE8
+# CODE:       0010: FFF7F6FF C046FFF7 F3FFC046 00F006F8
+# CODE:       0020: C04600F0 03F800F0 02F87047 70477047
+# CODE:       0030: FEFFFFEB 020000EB F0FFFFFA FAFFFFFA
+# CODE:       0040: 1EFF2FE1 1EFF2FE1
+# CODE:     )
+
+# CODE:     Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00)
+# CODE:     Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CODE:     SectionData (
+# CODE:       0000: E50F0000 E80F0000 B90F0000 E80F0000
+# CODE:     )
+
+# When we get a good mach-o disassembler the above __text section content check can be change to be symbolic.
+# Verify the low (thumb) bit is set on the first and third pointers but not the second and fourth.
+
+
+
+# Input file one:
+#
+#      .align  2
+#      .code   16
+#  .globl _t1
+#  .thumb_func _t1
+#_t1:
+#    bl  _a1
+#    nop
+#    blx _a2
+#    nop
+#    blx _a2
+#    bl  _t1
+#    nop
+#    bl  _t1
+#    nop
+#    blx _t2
+#    nop
+#    blx  _t2
+#    bx   lr
+#
+#  .globl _t2
+#  .thumb_func _t2
+#_t2:
+#    bx   lr
+#
+#    .data
+#_d1:  .long _t2
+#      .long _a1
+
+
+
+# Input file two:
+#
+#      .align  2
+#      .code   32
+#  .globl _a1
+#_a1:
+#    bl  _a1
+#    blx _a2
+#    bl  _t1
+#    blx _t2
+#    bx   lr
+#
+#  .globl _a2
+#_a2:
+#    bx   lr
+#
+#    .data
+#_d2:  .long _t1
+#      .long _a1
+
+
+
+
diff --git a/test/mach-o/arm-shims.yaml b/test/mach-o/arm-shims.yaml
new file mode 100644 (file)
index 0000000..1b54de4
--- /dev/null
@@ -0,0 +1,126 @@
+# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/arm-shims.yaml \
+# RUN: -dylib %p/Inputs/armv7/libSystem.yaml -o %t
+# RUN: llvm-readobj -s -sd %t | FileCheck %s
+#
+# Test b from arm to thumb or vice versa has shims added.s
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
+                       0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
+                       0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
+    relocations:
+      - offset:          0x00000014
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000010
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000006
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000002
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _a1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            _t1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _a2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _t2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:   Section {
+# CHECK:     Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CHECK:     Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CHECK:     SectionData (
+# CHECK:       0000: 00BF00F0 10E800F0 19B80000 00F020E3
+# CHECK:       0010: 000000FA 0F0000EA 00BFFFF7 F8EF00F0
+# CHECK:       0020: 07B80000 00F020E3 F4FFFFFA 050000EA
+# CHECK:       0030: DFF804C0 FF446047 D4FFFFFF DFF804C0
+# CHECK:       0040: FF446047 E0FFFFFF 04C09FE5 0CC08FE0
+# CHECK:       0050: 1CFF2FE1 ADFFFFFF 04C09FE5 0CC08FE0
+# CHECK:       0060: 1CFF2FE1 B5FFFFFF
+# CHECK:     )
+
+# When we get a good mach-o disassembler the above __text section content check can be change to be symbolic.
+
+
+# Input file one:
+#
+#      .align  2
+#      .code   16
+#  .globl _t1
+#  .thumb_func _t1
+#_t1:
+#    nop
+#    blx _a2
+#    b   _a2
+#
+#      .code   32
+#  .align 2
+#  .globl _a1
+#_a1:
+#    nop
+#    blx _t2
+#    b   _t2
+
+
+
+# Input file two:
+#
+#      .align  2
+#      .code   16
+#  .globl _t2
+#  .thumb_func _t2
+#_t2:
+#    nop
+#    blx _a1
+#    b   _a1
+#
+#      .code   32
+#  .align 2
+#  .globl _a2
+#_a2:
+#    nop
+#    blx _t1
+#    b   _t1
diff --git a/test/mach-o/arm-subsections-via-symbols.yaml b/test/mach-o/arm-subsections-via-symbols.yaml
new file mode 100644 (file)
index 0000000..23c2847
--- /dev/null
@@ -0,0 +1,60 @@
+# RUN: lld -flavor darwin -arch armv7 %s -r -print_atoms -o %t | FileCheck %s
+#
+# Test that assembly written without .subsections_via_symbols is parsed so
+# that atoms are non-dead-strip and there is a layout-after references
+# chaining atoms together.
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x04, 0x10, 0x9F, 0xE5, 0x04, 0x20, 0x9F, 0xE5,
+                       0x1E, 0xFF, 0x2F, 0xE1, 0x78, 0x56, 0x34, 0x12,
+                       0x21, 0x43, 0x65, 0x87 ]
+local-symbols:
+  - name:            constants1
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000C
+  - name:            constants2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000010
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - name:            _foo
+# CHECK:    scope:           global
+# CHECK:    content:         [ 04, 10, 9F, E5, 04, 20, 9F, E5, 1E, FF, 2F, E1 ]
+# CHECK:    dead-strip:      never
+# CHECK:    references:
+# CHECK:      - kind:            layout-after
+# CHECK:        offset:          0
+# CHECK:        target:          constants1
+# CHECK:  - name:            constants1
+# CHECK:    content:         [ 78, 56, 34, 12 ]
+# CHECK:    dead-strip:      never
+# CHECK:    references:
+# CHECK:      - kind:            layout-after
+# CHECK:        offset:          0
+# CHECK:        target:          constants2
+# CHECK:  - name:            constants2
+# CHECK:    content:         [ 21, 43, 65, 87 ]
+# CHECK:    dead-strip:      never
diff --git a/test/mach-o/arm64-reloc-negDelta32-fixup.yaml b/test/mach-o/arm64-reloc-negDelta32-fixup.yaml
new file mode 100644 (file)
index 0000000..ee8686c
--- /dev/null
@@ -0,0 +1,124 @@
+# RUN: lld -flavor darwin -arch arm64 -r %s -o %t
+# RUN: lld -flavor darwin -arch arm64 -r %t -o %t2
+# RUN: llvm-objdump -s -section="__eh_frame" %t | FileCheck %s
+# RUN: llvm-objdump -s -section="__eh_frame" %t2 | FileCheck %s
+
+# The reference from FDE->CIE is implicitly created as a negDelta32.
+# We don't emit these in to the binary as relocations, so we need to
+# make sure that the offset in the FDE to the CIE is the correct value.
+# CHECK: {{[0-9abcdef]*}} 10000000 00000000 017a5200 01781e01
+# CHECK: {{[0-9abcdef]*}} 100c1f00 20000000 18000000 b8ffffff
+# Note, this one that matters               ^~~~~~~~
+# It needs to be 0x18 as that is the offset back to 0 where the CIE is.
+# CHECK: {{[0-9abcdef]*}} ffffffff 20000000 00000000 00480e10
+# CHECK: {{[0-9abcdef]*}} 9e019d02 00000000
+
+---  !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x80, 0x52,
+                       0xFD, 0x7B, 0xC1, 0xA8, 0xC0, 0x03, 0x5F, 0xD6 ]
+    relocations:
+      - offset:          0x00000010
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          6
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000008
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F,
+                       0x72, 0x6C, 0x64, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000030
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000050
+    content:         [ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x1E, 0x01,
+                       0x10, 0x0C, 0x1F, 0x00, 0x20, 0x00, 0x00, 0x00,
+                       0x18, 0x00, 0x00, 0x00, 0x94, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0E, 0x10,
+                       0x9E, 0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            L_str
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp2
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000030
+  - name:            ltmp3
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000050
+global-symbols:
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _puts
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
diff --git a/test/mach-o/arm64-relocs-errors-delta64-offset.yaml b/test/mach-o/arm64-relocs-errors-delta64-offset.yaml
new file mode 100644 (file)
index 0000000..d238097
--- /dev/null
@@ -0,0 +1,65 @@
+# RUN: not lld -flavor darwin -arch arm64 %s -r \
+# RUN: 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xFF, 0x83, 0x00, 0xD1, 0xE0, 0x0B, 0x00, 0xF9,
+                       0x08, 0x00, 0x40, 0xB9, 0x08, 0x0D, 0x00, 0x71,
+                       0x08, 0x09, 0x00, 0x71, 0xE8, 0x0F, 0x00, 0xB9,
+                       0xC8, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x14,
+                       0xE8, 0x03, 0x00, 0x32, 0x08, 0x01, 0x00, 0x12,
+                       0xE8, 0x7F, 0x00, 0x39, 0x02, 0x00, 0x00, 0x14 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x000000000001C348
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+
+# Make sure that the offsets of the subtractor and unsigned both match.
+# CHECK: bad relocation (paired relocs must have the same offset) in section __DATA/__data (r1_address=1, r1_type=1, r1_extern=1, r1_length=3, r1_pcrel=0, r1_symbolnum=1), (r2_address=0, r2_type=0, r2_extern=1, r2_length=3, r2_pcrel=0, r2_symbolnum=1)
+      - offset:          0x00000001
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _f1
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000001C348
+  - name:            _f2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000010
+  - name:            _f3
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000020
diff --git a/test/mach-o/arm64-section-order.yaml b/test/mach-o/arm64-section-order.yaml
new file mode 100644 (file)
index 0000000..50d6846
--- /dev/null
@@ -0,0 +1,67 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
+
+# Make sure that the sections are sorted.  Currently we want this order:
+# __text, __unwind_info
+
+# CHECK: Sections:
+# CHECK: 0 __text        {{.*}} TEXT
+# CHECK: 1 __compact_unwind {{.*}}
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       8
+    address:         0x0000000000000000
+    content:         [ 0xC0, 0x03, 0x5F, 0xD6, 0xC0, 0x03, 0x5F, 0xD6 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+global-symbols:
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z4foo2i
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000004
diff --git a/test/mach-o/bind-opcodes.yaml b/test/mach-o/bind-opcodes.yaml
new file mode 100644 (file)
index 0000000..ad8cd16
--- /dev/null
@@ -0,0 +1,143 @@
+# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t
+# RUN: obj2yaml %t | FileCheck %s
+#
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xF9,
+                       0x00, 0x01, 0x40, 0xF9, 0x01, 0x00, 0x00, 0x90,
+                       0x21, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x94,
+                       0x00, 0x00, 0x80, 0x52, 0xFD, 0x7B, 0xC1, 0xA8,
+                       0xC0, 0x03, 0x5F, 0xD6 ]
+    relocations:
+      - offset:          0x0000001C
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000018
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000014
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x000000000000002C
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            l_.str
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000002C
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000002C
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            ___stdoutp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fprintf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK:   BindOpcodes:
+# CHECK:     - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+# CHECK:       Imm:             1
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          dyld_stub_binder
+# CHECK:     - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+# CHECK:       Imm:             1
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+# CHECK:       Imm:             2
+# CHECK:       ULEBExtraData:
+# CHECK:         - 0x0000000000000000
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_DO_BIND
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          ___stdoutp
+# CHECK:     - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+# CHECK:       Imm:             2
+# CHECK:       ULEBExtraData:
+# CHECK:         - 0x0000000000000010
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_DO_BIND
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_DONE
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          ''
+
+# CHECK:   LazyBindOpcodes:
+# CHECK:     - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+# CHECK:       Imm:             2
+# CHECK:       ULEBExtraData:
+# CHECK:         - 0x0000000000000018
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+# CHECK:       Imm:             1
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          _fprintf
+# CHECK:     - Opcode:          BIND_OPCODE_DO_BIND
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_DONE
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          ''
+# CHECK:     - Opcode:          BIND_OPCODE_DONE
+# CHECK:       Imm:             0
+# CHECK:       Symbol:          ''
\ No newline at end of file
diff --git a/test/mach-o/cstring-sections.yaml b/test/mach-o/cstring-sections.yaml
new file mode 100644 (file)
index 0000000..433dffc
--- /dev/null
@@ -0,0 +1,65 @@
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t -print_atoms | FileCheck %s
+#
+# Test -keep_private_externs in -r mode.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __objc_methname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x61, 0x62, 0x63, 0x00, 0x64, 0x65, 0x66, 0x00 ]
+  - segment:         __TEXT
+    section:         __objc_classname
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000006
+    content:         [ 0x61, 0x62, 0x63, 0x00, 0x67, 0x68, 0x69, 0x00 ]
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x000000000000000A
+    content:         [ 0x61, 0x62, 0x63, 0x00, 0x6A, 0x6B, 0x6C, 0x00 ]
+
+
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 61, 62, 63, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_methname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 64, 65, 66, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_methname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 61, 62, 63, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_classname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 67, 68, 69, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __TEXT/__objc_classname
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 61, 62, 63, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:   - scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 6A, 6B, 6C, 00 ]
+# CHECK:     merge:           by-content
diff --git a/test/mach-o/data-in-code-load-command.yaml b/test/mach-o/data-in-code-load-command.yaml
new file mode 100644 (file)
index 0000000..0c84bd4
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -data_in_code_info -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_DATA_IN_CODE
+# CHECK:   cmdsize 16
+# CHECK:   dataoff
+# CHECK:   datasize
+
+# NO_DATA_IN_CODE_INFO-NOT: LC_DATA_IN_CODE
diff --git a/test/mach-o/data-only-dylib.yaml b/test/mach-o/data-only-dylib.yaml
new file mode 100644 (file)
index 0000000..541e02f
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test that a data-only dylib can be built.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _myData
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: _myData
diff --git a/test/mach-o/dead-strip-globals.yaml b/test/mach-o/dead-strip-globals.yaml
new file mode 100644 (file)
index 0000000..45d919d
--- /dev/null
@@ -0,0 +1,31 @@
+# RUN: lld -flavor darwin -arch x86_64 -dead_strip -export_dynamic %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s
+# RUN: lld -flavor darwin -arch x86_64 -export_dynamic -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s
+# RUN: lld -flavor darwin -arch x86_64 -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t2.dylib -print_atoms | FileCheck -check-prefix=CHECK2 %s
+
+# RUN: lld -flavor darwin -arch x86_64 -r %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t3.o
+# RUN: llvm-nm -m %t3.o | FileCheck -check-prefix=RELOCATABLE_SYMBOLS %s
+
+#
+# Test that -export_dynamic -dead-strip from removing globals.
+#
+
+---
+defined-atoms:
+  - name:            def
+    scope:           global
+    dead-strip:      never
+  - name:            dead
+    scope:           global
+shared-library-atoms:
+  - name:            dyld_stub_binder
+    load-name:       /usr/lib/libSystem.B.dylib
+    type:            unknown
+...
+
+# CHECK1:       name: def
+# CHECK1:       name: dead
+
+# CHECK2:       name: def
+# CHECK2-NOT:   name: dead
+
+# RELOCATABLE_SYMBOLS: external def
diff --git a/test/mach-o/debug-syms.yaml b/test/mach-o/debug-syms.yaml
new file mode 100644 (file)
index 0000000..2842872
--- /dev/null
@@ -0,0 +1,249 @@
+# RUN: lld -flavor darwin -arch x86_64 -o %t %s -dylib %p/Inputs/x86_64/libSystem.yaml && \
+# RUN:   llvm-nm -no-sort -debug-syms %t | FileCheck %s
+
+# CHECK:      0000000000000000 - 00 0000    SO /Users/lhames/Projects/lld/lld-svn-tot/scratch/
+# CHECK-NEXT: 0000000000000000 - 00 0000    SO hw.c
+# CHECK-NEXT:    {{[0-9a-f]+}} - 03 0001   OSO {{.*}}{{/|\\}}test{{/|\\}}mach-o{{/|\\}}debug-syms.yaml
+# CHECK-NEXT: 0000000000000fa0 - 01 0000 BNSYM
+# CHECK-NEXT: 0000000000000fa0 - 01 0000   FUN _main
+# CHECK-NEXT: 0000000000000016 - 00 0000   FUN
+# CHECK-NEXT: 0000000000000016 - 01 0000 ENSYM
+# CHECK-NEXT: 0000000000000000 - 01 0000    SO
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+min-os-version-kind: LC_VERSION_MIN_MACOSX
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0xC7, 0x45,
+                       0xFC, 0x00, 0x00, 0x00, 0x00, 0x89, 0x7D, 0xF8,
+                       0x48, 0x89, 0x75, 0xF0, 0x5D, 0xC3 ]
+  - segment:         __DWARF
+    section:         __debug_str
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x0000000000000016
+    content:         [ 0x41, 0x70, 0x70, 0x6C, 0x65, 0x20, 0x4C, 0x4C,
+                       0x56, 0x4D, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
+                       0x6F, 0x6E, 0x20, 0x38, 0x2E, 0x30, 0x2E, 0x30,
+                       0x20, 0x28, 0x63, 0x6C, 0x61, 0x6E, 0x67, 0x2D,
+                       0x38, 0x30, 0x30, 0x2E, 0x30, 0x2E, 0x32, 0x34,
+                       0x2E, 0x31, 0x29, 0x00, 0x68, 0x77, 0x2E, 0x63,
+                       0x00, 0x2F, 0x55, 0x73, 0x65, 0x72, 0x73, 0x2F,
+                       0x6C, 0x68, 0x61, 0x6D, 0x65, 0x73, 0x2F, 0x50,
+                       0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x2F,
+                       0x6C, 0x6C, 0x64, 0x2F, 0x6C, 0x6C, 0x64, 0x2D,
+                       0x73, 0x76, 0x6E, 0x2D, 0x74, 0x6F, 0x74, 0x2F,
+                       0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x00,
+                       0x6D, 0x61, 0x69, 0x6E, 0x00, 0x69, 0x6E, 0x74,
+                       0x00, 0x61, 0x72, 0x67, 0x63, 0x00, 0x61, 0x72,
+                       0x67, 0x76, 0x00, 0x63, 0x68, 0x61, 0x72, 0x00 ]
+  - segment:         __DWARF
+    section:         __debug_loc
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x000000000000008E
+  - segment:         __DWARF
+    section:         __debug_abbrev
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x000000000000008E
+    content:         [ 0x01, 0x11, 0x01, 0x25, 0x0E, 0x13, 0x05, 0x03,
+                       0x0E, 0x10, 0x06, 0x1B, 0x0E, 0x11, 0x01, 0x12,
+                       0x01, 0x00, 0x00, 0x02, 0x2E, 0x01, 0x11, 0x01,
+                       0x12, 0x01, 0x40, 0x0A, 0x03, 0x0E, 0x3A, 0x0B,
+                       0x3B, 0x0B, 0x27, 0x0C, 0x49, 0x13, 0x3F, 0x0C,
+                       0x00, 0x00, 0x03, 0x05, 0x00, 0x02, 0x0A, 0x03,
+                       0x0E, 0x3A, 0x0B, 0x3B, 0x0B, 0x49, 0x13, 0x00,
+                       0x00, 0x04, 0x24, 0x00, 0x03, 0x0E, 0x3E, 0x0B,
+                       0x0B, 0x0B, 0x00, 0x00, 0x05, 0x0F, 0x00, 0x49,
+                       0x13, 0x00, 0x00, 0x00 ]
+  - segment:         __DWARF
+    section:         __debug_info
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x00000000000000DA
+    content:         [ 0x7F, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x56, 0x60, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
+                       0x6A, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x91,
+                       0x78, 0x69, 0x00, 0x00, 0x00, 0x01, 0x01, 0x6A,
+                       0x00, 0x00, 0x00, 0x03, 0x02, 0x91, 0x70, 0x6E,
+                       0x00, 0x00, 0x00, 0x01, 0x01, 0x71, 0x00, 0x00,
+                       0x00, 0x00, 0x04, 0x65, 0x00, 0x00, 0x00, 0x05,
+                       0x04, 0x05, 0x76, 0x00, 0x00, 0x00, 0x05, 0x7B,
+                       0x00, 0x00, 0x00, 0x04, 0x73, 0x00, 0x00, 0x00,
+                       0x06, 0x01, 0x00 ]
+    relocations:
+      - offset:          0x00000037
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x0000002F
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000026
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x0000001E
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __DWARF
+    section:         __debug_ranges
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x000000000000015D
+  - segment:         __DWARF
+    section:         __debug_macinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x000000000000015D
+    content:         [ 0x00 ]
+  - segment:         __DWARF
+    section:         __apple_names
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x000000000000015E
+    content:         [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x6A, 0x7F, 0x9A, 0x7C,
+                       0x2C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DWARF
+    section:         __apple_objc
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x000000000000019A
+    content:         [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00,
+                       0xFF, 0xFF, 0xFF, 0xFF ]
+  - segment:         __DWARF
+    section:         __apple_namespac
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x00000000000001BE
+    content:         [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00,
+                       0xFF, 0xFF, 0xFF, 0xFF ]
+  - segment:         __DWARF
+    section:         __apple_types
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x00000000000001E2
+    content:         [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00,
+                       0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                       0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00,
+                       0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0B, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+                       0x30, 0x80, 0x88, 0x0B, 0x63, 0x20, 0x95, 0x7C,
+                       0x40, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00,
+                       0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+                       0x6A, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x24,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DWARF
+    section:         __apple_exttypes
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x0000000000000248
+    content:         [ 0x48, 0x53, 0x41, 0x48, 0x01, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x06, 0x00,
+                       0xFF, 0xFF, 0xFF, 0xFF ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    alignment:       8
+    address:         0x0000000000000270
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000290
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x50, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DWARF
+    section:         __debug_line
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_DEBUG ]
+    address:         0x00000000000002D0
+    content:         [ 0x37, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1B, 0x00,
+                       0x00, 0x00, 0x01, 0x01, 0xFB, 0x0E, 0x0D, 0x00,
+                       0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x01, 0x00, 0x68, 0x77, 0x2E, 0x63,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x05, 0x03, 0x0A, 0x08, 0x3D, 0x02, 0x02,
+                       0x00, 0x01, 0x01 ]
+    relocations:
+      - offset:          0x00000028
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
diff --git a/test/mach-o/demangle.yaml b/test/mach-o/demangle.yaml
new file mode 100644 (file)
index 0000000..333a59e
--- /dev/null
@@ -0,0 +1,74 @@
+# REQUIRES: system-linker-mach-o
+#
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s  \
+# RUN:     -dylib -o %t %p/Inputs/x86_64/libSystem.yaml  2> %t.err
+# RUN: FileCheck %s < %t.err
+#
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN:     -dylib -o %t %p/Inputs/x86_64/libSystem.yaml -demangle 2> %t.err2
+# RUN: FileCheck %s --check-prefix=DCHECK < %t.err2
+#
+# Test -demangle option works on undefined symbol errors.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00,
+                       0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x0000000B
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000006
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000001
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            __Z1xv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __Znam
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __Znotcpp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:  __Znotcpp
+# CHECK:  __Znam
+# CHECK:  _foo
+
+# DCHECK:  __Znotcpp
+# DCHECK: operator new[](unsigned long)
+# DCHECK:  _foo
+
diff --git a/test/mach-o/dependency_info.yaml b/test/mach-o/dependency_info.yaml
new file mode 100644 (file)
index 0000000..2ec59b8
--- /dev/null
@@ -0,0 +1,19 @@
+# Test -dependency_info option
+#
+# RUN: lld -flavor darwin -arch x86_64 -test_file_usage  \
+# RUN:        -dependency_info %t.info \
+# RUN:        -path_exists /System/Library/Frameworks \
+# RUN:        -path_exists /System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -framework Bar \
+# RUN:        -framework Foo
+# RUN: %python %p/Inputs/DependencyDump.py %t.info | FileCheck %s
+
+
+# CHECK: linker-vers: lld
+# CHECK: input-file:  /Custom/Frameworks{{[/\\]}}Bar.framework{{[/\\]}}Bar
+# CHECK: not-found:   /Custom/Frameworks{{[/\\]}}Foo.framework{{[/\\]}}Foo
+# CHECK: input-file:  /System/Library/Frameworks{{[/\\]}}Foo.framework{{[/\\]}}Foo
+# CHECK: output-file: a.out
diff --git a/test/mach-o/do-not-emit-unwind-fde-arm64.yaml b/test/mach-o/do-not-emit-unwind-fde-arm64.yaml
new file mode 100644 (file)
index 0000000..70f76b5
--- /dev/null
@@ -0,0 +1,208 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t | FileCheck -check-prefix=CODE %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t2 | FileCheck -check-prefix=CODE %s
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x80, 0x52,
+                       0xFD, 0x7B, 0xC1, 0xA8, 0xC0, 0x03, 0x5F, 0xD6 ]
+    relocations:
+      - offset:          0x00000010
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          9
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000008
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F,
+                       0x72, 0x6C, 0x64, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000030
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000050
+    content:         [ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78,
+                       0x1E, 0x07, 0x00, 0x9D, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0x00, 0x10, 0x0C, 0x1F, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+                       0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x48, 0x0E, 0x10, 0x9E, 0x01, 0x9D, 0x02 ]
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x00000000000000A0
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            L_str
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            ltmp2
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000030
+  - name:            ltmp3
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000050
+  - name:            ltmp4
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000070
+global-symbols:
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __gxx_personality_v0
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _puts
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        L{{[0-9]*}}
+# CHECK:     scope:           hidden
+# CHECK:     type:            c-string
+# CHECK:     content:         [ 48, 65, 6C, 6C, 6F, 20, 77, 6F, 72, 6C, 64, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:   - ref-name:        L{{[0-9]*}}
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 1C, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 50, 4C,
+# CHECK:                        52, 00, 01, 78, 1E, 07, 00, {{..}}, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                        {{..}}, {{..}}, {{..}}, 00, 10, 0C, 1F, 00 ]
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 24, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                        {{..}}, {{..}}, {{..}}, {{..}}, 20, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 48, 0E, 10,
+# CHECK:                        9E, 01, 9D, 02 ]
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3fooi
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          25
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:   - ref-name:        L{{[0-9]*}}
+# CHECK:     type:            unwind-lsda
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 20, 00, 00, 00,
+# CHECK:                        00, 00, 00, 03, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:     alignment:       8
+# CHECK:     references:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          __Z3fooi
+# CHECK:   - name:            __Z3fooi
+# CHECK:     scope:           global
+# CHECK:     content:         [ FD, 7B, BF, A9, FD, 03, 00, 91, 00, 00, 00, 90,
+# CHECK:                        00, 00, 00, 91, 00, 00, 00, 94, 00, 00, 80, 52,
+# CHECK:                        FD, 7B, C1, A8, C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK:     references:
+# CHECK:       - kind:            page21
+# CHECK:         offset:          8
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:       - kind:            offset12
+# CHECK:         offset:          12
+# CHECK:         target:          L{{[0-9]*}}
+# CHECK:       - kind:            branch26
+# CHECK:         offset:          16
+# CHECK:         target:          _puts
+
+# Make sure we don't have any relocations in the __eh_frame section
+# CODE-NOT: RELOCATION RECORDS FOR [__eh_frame]
+
+# Also make sure the reloc for the FDE->function is the correct offset
+# It should be the offset from the fixup location back to the address
+# of the function we are referencing
+# CODE: Contents of section __eh_frame:
+# This is the CIE:
+# CODE-NEXT: {{[0-9abcdef]*}} 1c000000 00000000 017a504c 52000178
+# CODE-NEXT: {{[0-9abcdef]*}} 1e0700bd ffffffff ffffff00 100c1f00
+# This is the FDE:
+# CODE-NEXT: {{[0-9abcdef]*}} 24000000 24000000 a8ffffff ffffffff
+# This is the important offset for FDE->func    ^~~~~~~~ ~~~~~~~~
+
+# CODE-NEXT: {{[0-9abcdef]*}} 20000000 00000000 08c3ffff ffffffff
+# And this is the offset for FDE->lsda            ^~~~~~~~ ~~~~~~
+# CODE-NEXT: {{[0-9abcdef]*}} ff480e10 9e019d02
+# And this byte               ^~
diff --git a/test/mach-o/dso_handle.yaml b/test/mach-o/dso_handle.yaml
new file mode 100644 (file)
index 0000000..0796c2e
--- /dev/null
@@ -0,0 +1,62 @@
+# RUN: lld -flavor darwin -arch x86_64  %s  %p/Inputs/x86_64/libSystem.yaml -o %t1
+# RUN: llvm-nm -m -n %t1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/x86_64/libSystem.yaml -dead_strip -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/x86_64/libSystem.yaml -dylib -o %t3
+# RUN: llvm-nm -m -n %t3 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/x86_64/libSystem.yaml -bundle -o %t4
+# RUN: llvm-nm -m -n %t4 | FileCheck %s
+#
+# Test that ___dso_handle symbol is available for executables, bundles, and dylibs
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _d
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000008
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            ___dso_handle
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK_NOT:   ___dso_handle
+# CHECK:      _main
diff --git a/test/mach-o/dylib-install-names.yaml b/test/mach-o/dylib-install-names.yaml
new file mode 100644 (file)
index 0000000..af00adf
--- /dev/null
@@ -0,0 +1,74 @@
+# Check we accept -install_name correctly:
+# RUN: lld -flavor darwin -arch x86_64 -install_name libwibble.dylib -dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
+# RUN:     %p/Inputs/x86_64/libSystem.yaml %s -o %t.dylib
+# RUN: llvm-objdump -private-headers %t.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+# Check we read LC_ID_DYLIB correctly:
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/use-dylib-install-names.yaml \
+# RUN:      %p/Inputs/x86_64/libSystem.yaml %t.dylib -dylib -o %t2.dylib
+# RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-READ
+
+# Check we default the install-name to the output file:
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o libwibble.dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
+# RUN:     %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -private-headers libwibble.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+# RUN: rm -f libwibble.dylib
+
+# Check -single_module does nothing
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -install_name libwibble.dylib \
+# RUN:     -compatibility_version 2.0 -current_version 5.3 \
+# RUN:     -single_module -o %t2.dylib %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+global-symbols:
+  - name:            _myGlobal
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+...
+
+
+# CHECK-BINARY-WRITE: cmd LC_ID_DYLIB
+# CHECK-BINARY-WRITE-NEXT: cmdsize 40
+# CHECK-BINARY-WRITE-NEXT:  name libwibble.dylib (offset 24)
+# CHECK-BINARY-WRITE-NEXT:  time stamp 1
+# CHECK-BINARY-WRITE-NEXT:  current version 5.3.0
+# CHECK-BINARY-WRITE-NEXT:  compatibility version 2.0.0
+
+# CHECK-BINARY-READ: cmd LC_LOAD_DYLIB
+# CHECK-BINARY-READ-NEXT: cmdsize 56
+# CHECK-BINARY-READ-NEXT:  name /usr/lib/libSystem.B.dylib (offset 24)
+# CHECK-BINARY-READ-NEXT:  time stamp 2
+# CHECK-BINARY-READ-NEXT:  current version 1.0.0
+# CHECK-BINARY-READ-NEXT:  compatibility version 1.0.0
+
+# CHECK-BINARY-READ: cmd LC_LOAD_DYLIB
+# CHECK-BINARY-READ-NEXT: cmdsize 40
+# CHECK-BINARY-READ-NEXT:  name libwibble.dylib (offset 24)
+# CHECK-BINARY-READ-NEXT:  time stamp 2
+# CHECK-BINARY-READ-NEXT:  current version 5.3.0
+# CHECK-BINARY-READ-NEXT:  compatibility version 2.0.0
diff --git a/test/mach-o/eh-frame-relocs-arm64.yaml b/test/mach-o/eh-frame-relocs-arm64.yaml
new file mode 100644 (file)
index 0000000..e23dd7c
--- /dev/null
@@ -0,0 +1,318 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t | FileCheck -check-prefix=CODE %s
+# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t2 | FileCheck -check-prefix=CODE %s
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC0, 0x03, 0x5F, 0xD6, 0xC0, 0x03, 0x5F, 0xD6,
+                       0xC0, 0x03, 0x5F, 0xD6 ]
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000014
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000001C
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000020
+    content:         [ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000060
+    content:         [ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78,
+                       0x1E, 0x07, 0x9B, 0xED, 0xFF, 0xFF, 0xFF, 0x10,
+                       0x10, 0x0C, 0x1F, 0x00, 0x28, 0x00, 0x00, 0x00,
+                       0x20, 0x00, 0x00, 0x00, 0xDC, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x08, 0xCB, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x10, 0x9E,
+                       0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78,
+                       0x1E, 0x07, 0x9B, 0xA9, 0xFF, 0xFF, 0xFF, 0x10,
+                       0x10, 0x0C, 0x1F, 0x00, 0x28, 0x00, 0x00, 0x00,
+                       0x20, 0x00, 0x00, 0x00, 0x94, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x08, 0x83, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x10, 0x9E,
+                       0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x0000007D
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x0000007D
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+      - offset:          0x0000006C
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x0000006C
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          8
+      - offset:          0x0000005B
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          10
+      - offset:          0x00000035
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x00000035
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000024
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x00000024
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          7
+      - offset:          0x00000013
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          9
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _bar1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _bar2
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000018
+  - name:            ltmp12
+    type:            N_SECT
+    sect:            3
+    value:           0x000000000000001C
+  - name:            ltmp13
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000020
+  - name:            ltmp16
+    type:            N_SECT
+    sect:            5
+    value:           0x0000000000000060
+global-symbols:
+  - name:            __Z3fooi
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000008
+  - name:            __Z4foo2i
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            __gxx_personality_v0
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __gxx_personality_v1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000010
+  - name:            _someData
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x000000000000001C
+page-size:       0x00000000
+...
+
+# CHECK: --- !native
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        L000
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 18, 00, 00, 00, 00, 00, 00, 00, 03, 7A, 50, 4C,
+# CHECK:                        52, 00, 01, 78, 1E, 07, 9B, {{..}}, {{..}}, {{..}}, {{..}}, 10,
+# CHECK:                        10, 0C, 1F, 00 ]
+# CHECK:     alignment:       8
+# CHECK:     references:
+# CHECK:       - kind:            unwindCIEToPersonalityFunction
+# CHECK:         offset:          19
+# CHECK:         target:          __gxx_personality_v0
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 28, 00, 00, 00, 20, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                        {{..}}, {{..}}, {{..}}, {{..}}, 04, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 0E, 10, 9E,
+# CHECK:                        01, 9D, 02, 00, 00, 00, 00, 00 ]
+# CHECK:     alignment:       4 mod 8
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          L000
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3fooi
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          25
+# CHECK:         target:          _bar1
+# CHECK:   - ref-name:        L001
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 18, 00, 00, 00, 00, 00, 00, 00, 03, 7A, 50, 4C,
+# CHECK:                        52, 00, 01, 78, 1E, 07, 9B, {{..}}, {{..}}, {{..}}, {{..}}, 10,
+# CHECK:                        10, 0C, 1F, 00 ]
+# CHECK:     alignment:       8
+# CHECK:     references:
+# CHECK:       - kind:            unwindCIEToPersonalityFunction
+# CHECK:         offset:          19
+# CHECK:         target:          __gxx_personality_v1
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 28, 00, 00, 00, 20, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                        {{..}}, {{..}}, {{..}}, {{..}}, 04, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 0E, 10, 9E,
+# CHECK:                        01, 9D, 02, 00, 00, 00, 00, 00 ]
+# CHECK:     alignment:       4 mod 8
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          L001
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z4foo2i
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          25
+# CHECK:         target:          _bar2
+# CHECK:   - name:            _bar1
+# CHECK:     type:            unwind-lsda
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - name:            _bar2
+# CHECK:     type:            unwind-lsda
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - name:            _someData
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:   - name:            __gxx_personality_v0
+# CHECK:     scope:           global
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            __gxx_personality_v1
+# CHECK:     scope:           global
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            __Z3fooi
+# CHECK:     scope:           global
+# CHECK:     content:         [ C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            __Z4foo2i
+# CHECK:     scope:           global
+# CHECK:     content:         [ C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK:   - name:            _main
+# CHECK:     scope:           global
+# CHECK:     content:         [ C0, 03, 5F, D6 ]
+# CHECK:     alignment:       4
+# CHECK: ...
+
+# # Make sure we don't have any relocations in the __eh_frame section
+# CODE-NOT: RELOCATION RECORDS FOR [__eh_frame]
+
+# Also make sure the reloc for the CIE->personality function is the
+# correct offset
+# It should be the offset from the fixup location back to the address
+# of the function we are referencing
+# CODE: Contents of section __eh_frame:
+# This is the CIE:
+# CODE-NEXT: {{[0-9abcdef]*}} 18000000 00000000 037a504c 52000178
+# CODE-NEXT: {{[0-9abcdef]*}} 1e079bd1 ffffff10 100c1f00 28000000
+# This is the important offset for CIE->pfunc
+#                                   ^~~~~~~~~
+# Then we have an FDE starting from 28000000 above
+# CODE-NEXT: {{[0-9abcdef]*}} 20000000 c8ffffff ffffffff 04000000
+# CODE-NEXT: {{[0-9abcdef]*}} 00000000 08c3ffff ffffffff ff0e109e
+# And a new CIE starts at this 00000018 right below here
+# CODE-NEXT: {{[0-9abcdef]*}} 019d0200 00000000 18000000 00000000
+# CODE-NEXT: {{[0-9abcdef]*}} 037a504c 52000178 1e079b8d ffffff10
+# This is the important offset for its CIE->pfunc     ^~~~~~~~~
\ No newline at end of file
diff --git a/test/mach-o/error-simulator-vs-macosx.yaml b/test/mach-o/error-simulator-vs-macosx.yaml
new file mode 100644 (file)
index 0000000..bd62db3
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s %p/Inputs/hello-world-x86.yaml -o %t && llvm-nm -m %t | FileCheck %s
+# RUN: not lld -flavor darwin -arch i386 -ios_simulator_version_min 5.0 %s %p/Inputs/hello-world-x86.yaml -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+#
+# Test that i386 can link with a macos version but gives an error with a simululator version.
+#
+
+--- !mach-o
+arch:            x86
+OS:              Mac OS X
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x90 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+
+# ERROR: cannot be linked due to incompatible operating systems
diff --git a/test/mach-o/exe-offsets.yaml b/test/mach-o/exe-offsets.yaml
new file mode 100644 (file)
index 0000000..6a0e35c
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e start %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-readobj -sections %t | FileCheck %s
+
+# Make sure data gets put at offset
+
+--- !native
+defined-atoms:
+   - name:            start
+     scope:           global
+     content:         [ 90 ]
+
+   - name:            _s1
+     type:            data
+     content:         [ 31, 32, 33, 34 ]
+
+   - name:            _s2
+     type:            zero-fill
+     size:            8192
+
+   - name:            _s3
+     type:            zero-fill
+     size:            100
+
+   - name:            _s4
+     type:            data
+     content:         [ 01 ]
+
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __text
+# CHECK:     Segment: __TEXT
+# CHECK:     Size: 0x1
+# CHECK:     Offset: 0
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __data
+# CHECK:     Segment: __DATA
+# CHECK:     Size: 0x5
+# CHECK:     Offset: 4096
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __bss
+# CHECK:     Segment: __DATA
+# CHECK:     Size: 0x2064
+# CHECK:     Offset: 0
diff --git a/test/mach-o/exe-segment-overlap.yaml b/test/mach-o/exe-segment-overlap.yaml
new file mode 100644 (file)
index 0000000..47f0214
--- /dev/null
@@ -0,0 +1,44 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
+
+--- !native
+defined-atoms:
+   - name:            _main
+     scope:           global
+     content:         [ 90 ]
+
+   - name:            _s2
+     type:            data
+     content:         [ 31, 32, 33, 34 ]
+
+   - name:            _kustom
+     scope:           global
+     type:            unknown
+     content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+     section-choice:  custom-required
+     section-name:    __CUST/__custom
+
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __text
+# CHECK:     Segment: __TEXT
+# CHECK:     Size: 0x1
+# CHECK:     Offset: 4095
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __data
+# CHECK:     Segment: __DATA
+# CHECK:     Size: 0x4
+# CHECK:     Offset: 4096
+# CHECK:     SectionData (
+# CHECK-NEXT: 0000: 31323334
+# CHECK-NEXT: )
+
+# CHECK-LABEL: Section {
+# CHECK:     Name: __custom{{ }}
+# CHECK:     Segment: __CUST{{ }}
+# CHECK:     Size: 0x8
+# CHECK:     Offset: 8192
+# CHECK:     SectionData (
+# CHECK-NEXT: 0000: 01020304 05060708
+# CHECK-NEXT: )
diff --git a/test/mach-o/executable-exports.yaml b/test/mach-o/executable-exports.yaml
new file mode 100644 (file)
index 0000000..f16cbd5
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 \
+# RUN:      %s %p/Inputs/x86_64/libSystem.yaml -o %t  && \
+# RUN: llvm-objdump -exports-trie %t | FileCheck %s
+#
+#
+# Tests that exports trie builds properly.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3, 0xC3, 0xC3, 0xC3 ]
+global-symbols:
+  - name:            _myHidden
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _myRegular
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000002
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000003
+...
+
+# CHECK-NOT:  _myHidden
+# CHECK:      0x100000FFD  _myRegular
+# CHECK:      0x100000FFE  _myWeak [weak_def]
diff --git a/test/mach-o/export-trie-order.yaml b/test/mach-o/export-trie-order.yaml
new file mode 100644 (file)
index 0000000..a11c998
--- /dev/null
@@ -0,0 +1,62 @@
+# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
+# RUN: llvm-objdump -exports-trie %t | FileCheck %s
+#
+# Test that the export trie is emitted in order.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x58, 0x8D, 0x80, 0x16, 0x00,
+                       0x00, 0x00, 0x89, 0x04, 0x24, 0xE8, 0xE6, 0xFF,
+                       0xFF, 0xFF, 0x31, 0xC0, 0x83, 0xC4, 0x08, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000016
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000E
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000021
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000B
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000021
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: Exports trie:
+# CHECK-NEXT: __mh_execute_header
+# CHECK-NEXT: _main
diff --git a/test/mach-o/exported_symbols_list-dylib.yaml b/test/mach-o/exported_symbols_list-dylib.yaml
new file mode 100644 (file)
index 0000000..f9de5fe
--- /dev/null
@@ -0,0 +1,77 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/x86_64/libSystem.yaml -o %t \
+# RUN:      -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/x86_64/libSystem.yaml -o %t2 \
+# RUN:      -exported_symbol _foo -exported_symbol _b  && \
+# RUN: llvm-nm -m %t2 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/x86_64/libSystem.yaml -o %t3 \
+# RUN:      -unexported_symbol _bar -unexported_symbol _a  && \
+# RUN: llvm-nm -m %t3 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/x86_64/libSystem.yaml -dead_strip -o %t \
+# RUN:      -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \
+# RUN: llvm-nm -m %t | FileCheck -check-prefix=CHECK_DEAD %s
+#
+# Test -exported_symbols_list and -exported_symbol properly changes visibility.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) non-external (was a private external) _a
+# CHECK: (__DATA,__data) external _b
+# CHECK: (__TEXT,__text) non-external (was a private external) _bar
+# CHECK: (__TEXT,__text) external _foo
+
+# CHECK_DEAD-NOT:  (__DATA,__data) non-external (was a private external) _a
+# CHECK_DEAD:      (__DATA,__data) external _b
+# CHECK_DEAD-NOT:  (__TEXT,__text) non-external (was a private external) _bar
+# CHECK_DEAD:      (__TEXT,__text) external _foo
diff --git a/test/mach-o/exported_symbols_list-obj.yaml b/test/mach-o/exported_symbols_list-obj.yaml
new file mode 100644 (file)
index 0000000..31b325c
--- /dev/null
@@ -0,0 +1,67 @@
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t -exported_symbol _bar \
+# RUN:    && llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t2 -keep_private_externs \
+# RUN:      -exported_symbol _bar && \
+# RUN: llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
+#
+# RUN: not lld -flavor darwin -arch x86_64 -r  %s -o %t3  \
+# RUN:      -exported_symbol _foo 2> %t4
+
+# Test -exported_symbols_list properly changes visibility in -r mode.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT  ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) non-external (was a private external) _a
+# CHECK: (__DATA,__data) non-external (was a private external) _b
+# CHECK: (__TEXT,__text) external _bar
+# CHECK: (__TEXT,__text) non-external (was a private external) _foo
+
+# CHECK_KPE: (__DATA,__data) non-external (was a private external) _a
+# CHECK_KPE: (__DATA,__data) private external _b
+# CHECK_KPE: (__TEXT,__text) external _bar
+# CHECK_KPE: (__TEXT,__text) private external _foo
diff --git a/test/mach-o/exported_symbols_list-undef.yaml b/test/mach-o/exported_symbols_list-undef.yaml
new file mode 100644 (file)
index 0000000..377282f
--- /dev/null
@@ -0,0 +1,55 @@
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN:      %s %p/Inputs/x86_64/libSystem.yaml -o %t -exported_symbol _foobar 2> %t2
+#
+# Test -exported_symbol fails if exported symbol not found.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) private external _a
+# CHECK: (__DATA,__data) external _b
+# CHECK: (__TEXT,__text) private external _bar
+# CHECK: (__TEXT,__text) external _foo
diff --git a/test/mach-o/fat-archive.yaml b/test/mach-o/fat-archive.yaml
new file mode 100644 (file)
index 0000000..979ede3
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t \
+# RUN:    -L %p/Inputs -lfoo %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that fat archives are handled.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+                       0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+                       0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000012
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/filelist.yaml b/test/mach-o/filelist.yaml
new file mode 100644 (file)
index 0000000..28bfeb7
--- /dev/null
@@ -0,0 +1,18 @@
+# RUN: lld -flavor darwin -test_file_usage  \
+# RUN:    -filelist %p/Inputs/full.filelist \
+# RUN:        -path_exists /foo/bar/a.o \
+# RUN:        -path_exists /foo/bar/b.o \
+# RUN:        -path_exists /foo/x.a \
+# RUN: 2>&1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -test_file_usage -t \
+# RUN:    -filelist %p/Inputs/partial.filelist,/foo \
+# RUN:        -path_exists /foo/bar/a.o \
+# RUN:        -path_exists /foo/bar/b.o \
+# RUN:        -path_exists /foo/x.a \
+# RUN: 2>&1 | FileCheck %s
+
+
+# CHECK: Found filelist entry /foo/bar/a.o
+# CHECK: Found filelist entry /foo/bar/b.o
+# CHECK: Found filelist entry /foo/x.a
diff --git a/test/mach-o/flat_namespace_undef_error.yaml b/test/mach-o/flat_namespace_undef_error.yaml
new file mode 100644 (file)
index 0000000..af84608
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined error %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
+
+# Make sure we error out for -flat_namespace -undefined error.
+# CHECK: Undefined symbol: : _bar
diff --git a/test/mach-o/flat_namespace_undef_suppress.yaml b/test/mach-o/flat_namespace_undef_suppress.yaml
new file mode 100644 (file)
index 0000000..e68fd99
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml
+#
+# Sanity check '-flat_namespace -undefined suppress'.
+# This should pass without error, even though '_bar' is undefined.
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
diff --git a/test/mach-o/force_load-dylib.yaml b/test/mach-o/force_load-dylib.yaml
new file mode 100644 (file)
index 0000000..d32c63e
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN:     -install_name /usr/lib/libbar.dylib %p/Inputs/x86_64/libSystem.yaml -o %t1.dylib
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -all_load %t1.dylib \
+# RUN:      -install_name /usr/lib/libfoo.dylib %p/Inputs/x86_64/libSystem.yaml -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+#
+# Test -all_load does not break linking with dylibs
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: (__TEXT,__text) external _foo
diff --git a/test/mach-o/force_load-x86_64.yaml b/test/mach-o/force_load-x86_64.yaml
new file mode 100644 (file)
index 0000000..5b37f47
--- /dev/null
@@ -0,0 +1,38 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/x86_64/libSystem.yaml \
+# RUN:      %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t1
+# RUN: llvm-nm -m -n %t1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/x86_64/libSystem.yaml \
+# RUN:      -force_load %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck --check-prefix=CHECKF %s
+#
+# Test that -force_load causes members of static library to be loaded.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK:      {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK-NOT:   {{[0-9a-f]+}} (__TEXT,__text) external _main
+
+# CHECKF:     {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECKF:     {{[0-9a-f]+}} (__TEXT,__text) external _foo
+# CHECKF-NOT: {{[0-9a-f]+}} (__TEXT,__text) external _bar
diff --git a/test/mach-o/framework-user-paths.yaml b/test/mach-o/framework-user-paths.yaml
new file mode 100644 (file)
index 0000000..80d6e3b
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# Test framework and SDK search paths.
+#   myFrameworks is not an absolute path, so it should not by found in SDK
+#   /Custom/Frameworks should be found in SDK
+#   /opt/Frameworks should not be found in SDK
+#   /System/Library/Frameworks is implicit and should be in SDK
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists myFrameworks \
+# RUN:        -path_exists myFrameworks/my.framework/my \
+# RUN:        -path_exists /opt/Frameworks \
+# RUN:        -path_exists /opt/Frameworks/other.framework/other \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /System/Library/Frameworks \
+# RUN:        -path_exists /System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -path_exists /SDK/myFrameworks \
+# RUN:        -path_exists /SDK/myFrameworks/my.framework/my \
+# RUN:        -path_exists /SDK/Custom/Frameworks \
+# RUN:        -path_exists /SDK/Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /SDK/System/Library/Frameworks \
+# RUN:        -path_exists /SDK/System/Library/Frameworks/Foo.framework/Foo \
+# RUN:        -syslibroot /SDK \
+# RUN:        -FmyFrameworks \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -F/opt/Frameworks \
+# RUN:        -framework my \
+# RUN:        -framework Bar \
+# RUN:        -framework Foo \
+# RUN:        -framework other \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK:        Framework search paths:
+# CHECK-NEXT:     myFrameworks
+# CHECK-NEXT:     /SDK/Custom/Frameworks
+# CHECK-NEXT:     /opt/Frameworks
+# CHECK-NEXT:     /SDK/System/Library/Frameworks
+# CHECK: Found framework myFrameworks/my.framework/my
+# CHECK: Found framework /SDK/Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found framework /SDK/System/Library/Frameworks/Foo.framework/Foo
+# CHECK: Found framework /opt/Frameworks/other.framework/other
diff --git a/test/mach-o/function-starts-load-command.yaml b/test/mach-o/function-starts-load-command.yaml
new file mode 100644 (file)
index 0000000..5cfe9dc
--- /dev/null
@@ -0,0 +1,32 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_FUNCTION_STARTS
+# CHECK:   cmdsize 16
+# CHECK:   dataoff
+# CHECK:   datasize
+
+# NO_FUNCTION_STARTS-NOT: LC_FUNCTION_STARTS
diff --git a/test/mach-o/gcc_except_tab-got-arm64.yaml b/test/mach-o/gcc_except_tab-got-arm64.yaml
new file mode 100644 (file)
index 0000000..47b174d
--- /dev/null
@@ -0,0 +1,53 @@
+# RUN: lld -flavor darwin -arch arm64 %s \
+# RUN: -dylib %p/Inputs/arm64/libSystem.yaml -o %t
+# RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+# Make sure that the GOT relocation from gcc_except_tab to the data
+# is not removed.
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ FD, 7B, BF, A9, FD, 03, 00, 91, FF, 43, 00, D1,
+                       BF, C3, 1F, B8, 00, 00, 00, 94, BF, 03, 00, 91,
+                       FD, 7B, C1, A8, C0, 03, 5F, D6 ]
+    alignment:       4
+  - name:            __ZTSP1A
+    scope:           hidden
+    type:            constant
+    content:         [ 50, 31, 41, 00 ]
+    merge:           as-weak
+  - name:            GCC_except_table0
+    type:            unwind-lsda
+    content:         [ FF, 9B, E7, 80, 00, 03, 5B, 00, 00, 00, 00, 1C,
+                       00, 00, 00, 00, 00, 00, 00, 00, 1C, 00, 00, 00,
+                       18, 00, 00, 00, 84, 00, 00, 00, 03, 40, 00, 00,
+                       00, 10, 00, 00, 00, 94, 00, 00, 00, 03, 60, 00,
+                       00, 00, 20, 00, 00, 00, B4, 00, 00, 00, 05, 80,
+                       00, 00, 00, 68, 00, 00, 00, 00, 00, 00, 00, 00,
+                       E8, 00, 00, 00, 08, 00, 00, 00, 28, 01, 00, 00,
+                       00, F0, 00, 00, 00, 74, 00, 00, 00, 00, 00, 00,
+                       00, 00, 00, 00, 01, 7D, 01, 00, A8, FF, FF, FF ]
+    alignment:       4
+    references:
+      - kind:            delta32ToGOT
+        offset:          104
+        target:          __ZTIP1A
+  - name:            __ZTIP1A
+    scope:           hidden
+    type:            data
+    content:         [ 10, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+                       00, 00, 00, 80, 00, 00, 00, 00, 00, 00, 00, 00,
+                       00, 00, 00, 00, 00, 00, 00, 00 ]
+    merge:           as-weak
+    alignment:       16
+shared-library-atoms:
+  - name:            dyld_stub_binder
+    load-name:       /usr/lib/libSystem.B.dylib
+    type:            unknown
+...
+
+# Make sure we have a GOT relocation.
+# This could only have come from __gcc_except_tab to __ZTIP1A
+# CHECK: __got
\ No newline at end of file
diff --git a/test/mach-o/got-order.yaml b/test/mach-o/got-order.yaml
new file mode 100644 (file)
index 0000000..2e8579c
--- /dev/null
@@ -0,0 +1,69 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/got-order.yaml \
+# RUN: %p/Inputs/got-order2.yaml -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -bind %t | FileCheck %s
+#
+# Test that GOT slots are sorted by name
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x0D, 0x00,
+                       0x00, 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x8B, 0x00, 0x03, 0x01, 0x48, 0x8B,
+                       0x0D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000019
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000000E
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000007
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+global-symbols:
+  - name:            _func
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _aaa
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fff
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _zzz
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK:           __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _aaa
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _bar
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _fff
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _foo
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _zazzle
+# CHECK-NEXT:  __DATA   __got  {{[0-9a-zA-Z _]+}} pointer   0 libfoobar     _zzz
diff --git a/test/mach-o/hello-world-arm64.yaml b/test/mach-o/hello-world-arm64.yaml
new file mode 100644 (file)
index 0000000..138af59
--- /dev/null
@@ -0,0 +1,102 @@
+# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+# RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-PRIVATE-HEADER
+#
+# Test that arm64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xF9,
+                       0x00, 0x01, 0x40, 0xF9, 0x01, 0x00, 0x00, 0x90,
+                       0x21, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x94,
+                       0x00, 0x00, 0x80, 0x52, 0xFD, 0x7B, 0xC1, 0xA8,
+                       0xC0, 0x03, 0x5F, 0xD6 ]
+    relocations:
+      - offset:          0x0000001C
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000018
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000014
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x000000000000002C
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            l_.str
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000002C
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000002C
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            ___stdoutp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fprintf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       (undefined) external ___stdoutp (from libSystem)
+# CHECK:       (undefined) external _fprintf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+
+# CHECK-PRIVATE-HEADER: sectname __stubs
+# CHECK-PRIVATE-HEADER-NEXT:  segname __TEXT
+# CHECK-PRIVATE-HEADER-NEXT:     addr
+# CHECK-PRIVATE-HEADER-NEXT:     size
+# CHECK-PRIVATE-HEADER-NEXT:   offset
+# CHECK-PRIVATE-HEADER-NEXT:    align 2^1 (2)
diff --git a/test/mach-o/hello-world-armv6.yaml b/test/mach-o/hello-world-armv6.yaml
new file mode 100644 (file)
index 0000000..8a9edee
--- /dev/null
@@ -0,0 +1,64 @@
+# RUN: lld -flavor darwin -arch armv6 %s %p/Inputs/hello-world-armv6.yaml -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that armv6 (arm) hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            armv6
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x80, 0x40, 0x2D, 0xE9, 0x10, 0x00, 0x9F, 0xE5,
+                       0x0D, 0x70, 0xA0, 0xE1, 0x00, 0x00, 0x8F, 0xE0,
+                       0xFA, 0xFF, 0xFF, 0xEB, 0x00, 0x00, 0xA0, 0xE3,
+                       0x80, 0x80, 0xBD, 0xE8, 0x0C, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000010
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       (undefined) external _printf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-armv7.yaml b/test/mach-o/hello-world-armv7.yaml
new file mode 100644 (file)
index 0000000..1871d68
--- /dev/null
@@ -0,0 +1,76 @@
+# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/hello-world-armv7.yaml -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that armv7 (thumb) hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x80, 0xB5, 0x40, 0xF2, 0x06, 0x00, 0x6F, 0x46,
+                       0xC0, 0xF2, 0x00, 0x00, 0x78, 0x44, 0xFF, 0xF7,
+                       0xF8, 0xEF, 0x00, 0x20, 0x80, 0xBD ]
+    relocations:
+      - offset:          0x0000000E
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000008
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x00000016
+      - offset:          0x00000006
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000002
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000016
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000016
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       (undefined) external _printf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external [Thumb] _main
diff --git a/test/mach-o/hello-world-x86.yaml b/test/mach-o/hello-world-x86.yaml
new file mode 100644 (file)
index 0000000..779b681
--- /dev/null
@@ -0,0 +1,62 @@
+# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that i386 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x58, 0x8D, 0x80, 0x16, 0x00,
+                       0x00, 0x00, 0x89, 0x04, 0x24, 0xE8, 0xE6, 0xFF,
+                       0xFF, 0xFF, 0x31, 0xC0, 0x83, 0xC4, 0x08, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000016
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000E
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000021
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000B
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000021
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       (undefined) external _printf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-x86_64.yaml b/test/mach-o/hello-world-x86_64.yaml
new file mode 100644 (file)
index 0000000..8803c44
--- /dev/null
@@ -0,0 +1,120 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/hello-world-x86_64.yaml \
+# RUN: -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/hello-world-x86_64.yaml \
+# RUN: -dead_strip -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck %s
+#
+# Test that x86_64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x05, 0x00,
+                       0x00, 0x00, 0x00, 0x48, 0x8B, 0x38, 0x48, 0x8D,
+                       0x35, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8,
+                       0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000018
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000011
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          0
+      - offset:          0x00000007
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000028
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000048
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x98, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            L1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            EH_frame0
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000048
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _main.eh
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x0000000000000060
+undefined-symbols:
+  - name:            ___stdoutp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fprintf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       (undefined) external ___stdoutp (from libSystem)
+# CHECK:       (undefined) external _fprintf (from libSystem)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) [referenced dynamically] external __mh_execute_header
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
diff --git a/test/mach-o/image-base.yaml b/test/mach-o/image-base.yaml
new file mode 100644 (file)
index 0000000..aa78fea
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-readobj -macho-segment %t | FileCheck %s
+# RUN: not lld -flavor darwin -arch x86_64 -image_base 0x31415926530 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED
+# RUN: not lld -flavor darwin -arch x86_64 -image_base 1000 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-OVERLAP
+# RUN: not lld -flavor darwin -arch x86_64 -image_base hithere %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX
+
+--- !native
+defined-atoms:
+   - name:            _main
+     scope:           global
+     content:         []
+
+# CHECK: Segment {
+# CHECK:   Cmd: LC_SEGMENT_64
+# CHECK:   Name: __TEXT
+# CHECK-NEXT:   Size: 152
+# CHECK-NEXT:   vmaddr: 0x31415926000
+# CHECK-NEXT:   vmsize: 0x1000
+
+
+# CHECK-ERROR-MISPAGED: error: image_base must be a multiple of page size (0x1000)
+
+# CHECK-ERROR-OVERLAP: error: image_base overlaps with __PAGEZERO
+
+# CHECK-ERROR-NOTHEX: error: image_base expects a hex number
diff --git a/test/mach-o/infer-arch.yaml b/test/mach-o/infer-arch.yaml
new file mode 100644 (file)
index 0000000..c09c94d
--- /dev/null
@@ -0,0 +1,29 @@
+# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s -r -o %t \
+# RUN: && lld -flavor darwin -r %t -o %t2 -print_atoms | FileCheck %s
+#
+# Test linker can detect architecture without -arch option.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: defined-atoms:
+# CHECK:  - name:            _foo
diff --git a/test/mach-o/interposing-section.yaml b/test/mach-o/interposing-section.yaml
new file mode 100644 (file)
index 0000000..ec4eaa3
--- /dev/null
@@ -0,0 +1,72 @@
+# RUN: lld -flavor darwin -arch x86_64  %s %p/Inputs/interposing-section.yaml \
+# RUN: -dylib -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64  %s -r -o %t1
+# RUN: llvm-objdump -private-headers %t1 | FileCheck %s
+#
+# Test that interposing section is preserved by linker.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __interpose
+    type:            S_INTERPOSING
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000010
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+local-symbols:
+  - name:            _my_open
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __interpose_open
+    type:            N_SECT
+    sect:            2
+    desc:            [ N_NO_DEAD_STRIP ]
+    value:           0x0000000000000010
+undefined-symbols:
+  - name:            _open
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK:         sectname __interposing
+# CHECK:          segname __DATA
+# CHECK:             type S_INTERPOSING
+
diff --git a/test/mach-o/keep_private_externs.yaml b/test/mach-o/keep_private_externs.yaml
new file mode 100644 (file)
index 0000000..e7adf18
--- /dev/null
@@ -0,0 +1,63 @@
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t \
+# RUN:    && llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -r  %s -o %t2 -keep_private_externs \
+# RUN:    && llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
+#
+# Test -keep_private_externs in -r mode.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000000C
+    content:         [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000000C
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            2
+    value:           0x0000000000000010
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT  ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) external _a
+# CHECK: (__DATA,__data) non-external (was a private external) _b
+# CHECK: (__TEXT,__text) external _bar
+# CHECK: (__TEXT,__text) non-external (was a private external) _foo
+
+# CHECK_KPE: (__DATA,__data) external _a
+# CHECK_KPE: (__DATA,__data) private external _b
+# CHECK_KPE: (__TEXT,__text) external _bar
+# CHECK_KPE: (__TEXT,__text) private external _foo
diff --git a/test/mach-o/lazy-bind-x86_64.yaml b/test/mach-o/lazy-bind-x86_64.yaml
new file mode 100644 (file)
index 0000000..5c588c5
--- /dev/null
@@ -0,0 +1,111 @@
+# REQUIRES: x86
+
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/lazy-bind-x86_64.yaml  %p/Inputs/lazy-bind-x86_64-2.yaml \
+# RUN: %p/Inputs/lazy-bind-x86_64-3.yaml -o %t  \
+# RUN:   %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -lazy-bind %t | FileCheck %s
+# RUN: llvm-nm -m %t | FileCheck --check-prefix=CHECK-NM %s
+# RUN: llvm-objdump -disassemble %t | FileCheck --check-prefix=CHECK-HELPERS %s
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DYLIBS %s
+#
+# Test that correct two-level namespace ordinals are used for lazy bindings.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8, 0x00, 0x00,
+                       0x00, 0x00, 0x31, 0xC0, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000015
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x0000000E
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000007
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _baz
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:    libbar        _bar
+# CHECK:    libbaz        _baz
+# CHECK:    libfoo        _foo
+
+
+# CHECK-NM:   (undefined) external _bar (from libbar)
+# CHECK-NM:   (undefined) external _baz (from libbaz)
+# CHECK-NM:   (undefined) external _foo (from libfoo)
+
+
+# CHECK-HELPERS:Disassembly of section __TEXT,__stub_helper:
+# CHECK-HELPERS:       68 00 00 00 00            pushq $0
+# CHECK-HELPERS:       68 10 00 00 00            pushq $16
+# CHECK-HELPERS:       68 20 00 00 00            pushq $32
+
+# Make sure the stub helper is correctly aligned
+# CHECK-DYLIBS:   sectname __stub_helper
+# CHECK-DYLIBS-NEXT:    segname __TEXT
+# CHECK-DYLIBS-NEXT:       addr
+# CHECK-DYLIBS-NEXT:       size
+# CHECK-DYLIBS-NEXT:     offset
+# CHECK-DYLIBS-NEXT:      align 2^2 (4)
+
+# Make sure the __nl_symbol_ptr section is used instea of __got as this is x86_64
+# CHECK-DYLIBS:   sectname __nl_symbol_ptr
+# CHECK-DYLIBS-NEXT:    segname __DATA
+
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libbar.dylib (offset 24)
+# CHECK-DYLIBS:       current version 2.3.0
+# CHECK-DYLIBS: compatibility version 1.0.0
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libfoo.dylib (offset 24)
+# CHECK-DYLIBS:       current version 3.4.0
+# CHECK-DYLIBS: compatibility version 2.0.0
+# CHECK-DYLIBS:           cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS:          name /usr/lib/libbaz.dylib (offset 24)
+# CHECK-DYLIBS:       current version 4.5.0
+# CHECK-DYLIBS: compatibility version 3.0.0
+
+
diff --git a/test/mach-o/lc_segment_filesize.yaml b/test/mach-o/lc_segment_filesize.yaml
new file mode 100644 (file)
index 0000000..4413c76
--- /dev/null
@@ -0,0 +1,31 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -o %t %s && llvm-objdump -private-headers %t | FileCheck %s
+
+# CHECK: filesize 19
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00 ]
+  - segment:         __TEXT
+    section:         __alt
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000010
+    content:         [ 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
diff --git a/test/mach-o/lib-search-paths.yaml b/test/mach-o/lib-search-paths.yaml
new file mode 100644 (file)
index 0000000..5005f01
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -r -print_atoms 2>&1  | FileCheck %s
+
+--- !native
+undefined-atoms:
+    - name: _from_myshared
+    - name: _from_mystatic
+    - name: _from_fileo
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _from_fileo
+# CHECK:     content:         [ 2A, 00, 00, 00 ]
+# CHECK:   - name:            _from_mystatic
+# CHECK:     content:         [ 02, 00, 00, 00 ]
+# CHECK: shared-library-atoms:
+# CHECK:   - name:            _from_myshared
+# CHECK:     load-name:       libmyshared.dylib
diff --git a/test/mach-o/library-order.yaml b/test/mach-o/library-order.yaml
new file mode 100644 (file)
index 0000000..b53232d
--- /dev/null
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %s -o %t \
+# RUN:    %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that if library is before object file on command line, it still is used.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+                       0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+                       0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000012
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/library-rescan.yaml b/test/mach-o/library-rescan.yaml
new file mode 100644 (file)
index 0000000..99c7b88
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \
+# RUN:    %s -o %t  %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that static libraries are automatically rescanned (bar needs foo).
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+                       0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+                       0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000012
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _bar
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/libresolve-bizarre-root-override.yaml b/test/mach-o/libresolve-bizarre-root-override.yaml
new file mode 100644 (file)
index 0000000..c65ca31
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: not lld -flavor darwin -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/lib/libSystem.dylib \
+# RUN:        -syslibroot /Applications/MySDK \
+# RUN:        -syslibroot / \
+# RUN:        -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+# When the last -syslibroot is simply "/", all of them get discarded. So in this
+# case, only /usr/lib should show up.
+
+# CHECK: Library search paths:
+# CHECK:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK: Unable to find library for -lSystem
diff --git a/test/mach-o/libresolve-multiple-syslibroots.yaml b/test/mach-o/libresolve-multiple-syslibroots.yaml
new file mode 100644 (file)
index 0000000..0b63eb6
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /Applications/MyFirstSDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MySecondSDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MyFirstSDK/usr/local/lib/libSystem.a \
+# RUN:        -path_exists /Applications/MySecondSDK/usr/local/lib/libSystem.a \
+# RUN:        -syslibroot /Applications/MyFirstSDK \
+# RUN:        -syslibroot /Applications/MySecondSDK \
+# RUN:        -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+
+# CHECK: Library search paths:
+# CHECK:     /usr/lib
+# CHECK:     /Applications/MyFirstSDK/usr/local/lib
+# CHECK:     /Applications/MySecondSDK/usr/local/lib
+# CHECK: Found library /Applications/MyFirstSDK/usr/local/lib/libSystem.a
diff --git a/test/mach-o/libresolve-one-syslibroot.yaml b/test/mach-o/libresolve-one-syslibroot.yaml
new file mode 100644 (file)
index 0000000..f9042fc
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/local/lib \
+# RUN:        -path_exists /Applications/MySDK/usr/local/lib/libSystem.a \
+# RUN:        -path_exists /hasFoo \
+# RUN:        -path_exists /hasFoo/foo.o \
+# RUN:        -syslibroot /Applications/MySDK \
+# RUN:        -L/hasFoo \
+# RUN:        -lSystem -lfoo.o \
+# RUN: 2>&1 | FileCheck %s
+
+# When just one -syslibroot is specified, we apparently want to skip *system*
+# paths that aren't found. User ones should still get added. In this case
+# /usr/lib exists, but not the equivalent in the -syslibroot, so there should be
+# no mention of /usr/lib.
+
+# CHECK: Library search paths:
+# CHECK:     /hasFoo
+# CHECK-NOT:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK:     /Applications/MySDK/usr/local/lib
+# CHECK-NOT:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK: Found library /Applications/MySDK/usr/local/lib/libSystem.a
+# CHECK: Found library /hasFoo/foo.o
diff --git a/test/mach-o/libresolve-simple.yaml b/test/mach-o/libresolve-simple.yaml
new file mode 100644 (file)
index 0000000..ffb045f
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /usr/local/lib \
+# RUN:        -path_exists /usr/lib/libSystem.dylib \
+# RUN:        -path_exists hasFoo \
+# RUN:        -path_exists hasFoo/libFoo.dylib \
+# RUN:        -path_exists /hasBar \
+# RUN:        -path_exists /hasBar/libBar.dylib \
+# RUN:        -L hasFoo \
+# RUN:        -L /hasBar \
+# RUN:        -lSystem -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK:     hasFoo
+# CHECK:     /hasBar
+# CHECK:     /usr/lib
+# CHECK:     /usr/local/lib
+# CHECK: Found library /usr/lib/libSystem.dylib
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /hasBar/libBar.dylib
diff --git a/test/mach-o/libresolve-user-paths.yaml b/test/mach-o/libresolve-user-paths.yaml
new file mode 100644 (file)
index 0000000..9fe8856
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists hasFoo \
+# RUN:        -path_exists hasFoo/libFoo.dylib \
+# RUN:        -path_exists /hasBar \
+# RUN:        -path_exists /hasBar/libBar.dylib \
+# RUN:        -path_exists /SDK/hasFoo \
+# RUN:        -path_exists /SDK/hasFoo/libFoo.dylib \
+# RUN:        -path_exists /SDK/hasBar \
+# RUN:        -path_exists /SDK/hasBar/libBar.dylib \
+# RUN:        -syslibroot /SDK \
+# RUN:        -L hasFoo \
+# RUN:        -L /hasBar \
+# RUN:        -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK:     hasFoo
+# CHECK:     /SDK/hasBar
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /SDK/hasBar/libBar.dylib
diff --git a/test/mach-o/libresolve-z.yaml b/test/mach-o/libresolve-z.yaml
new file mode 100644 (file)
index 0000000..1df7ece
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /usr/local/lib \
+# RUN:        -path_exists /usr/lib/libSystem.dylib \
+# RUN:        -path_exists hasFoo \
+# RUN:        -path_exists hasFoo/libFoo.dylib \
+# RUN:        -path_exists /hasBar \
+# RUN:        -path_exists /hasBar/libBar.dylib \
+# RUN:        -L hasFoo \
+# RUN:        -L /hasBar \
+# RUN:        -Z \
+# RUN:        -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK:     hasFoo
+# CHECK:     /hasBar
+# CHECK-NOT:     /usr/lib
+# CHECK-NOT:     /usr/local/lib
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /hasBar/libBar.dylib
diff --git a/test/mach-o/linker-as-ld.yaml b/test/mach-o/linker-as-ld.yaml
new file mode 100644 (file)
index 0000000..21afdb2
--- /dev/null
@@ -0,0 +1,32 @@
+# REQUIRES: system-linker-mach-o
+#
+# RUN: rm -rf %T/ld && ln -s `which lld` %T/ld \
+# RUN:  && %T/ld -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/linker-as-ld.yaml -o %t \
+# RUN:  && llvm-nm %t | FileCheck %s
+#
+# Test linker run as "ld" on darwin works as darwin linker.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK:                 T _main
diff --git a/test/mach-o/lit.local.cfg b/test/mach-o/lit.local.cfg
new file mode 100644 (file)
index 0000000..ccbf4e1
--- /dev/null
@@ -0,0 +1,4 @@
+
+# mach-o test cases encode input files in yaml and use .yaml extension
+config.suffixes = ['.yaml']
+config.excludes = ['Inputs']
diff --git a/test/mach-o/mach_header-cpusubtype.yaml b/test/mach-o/mach_header-cpusubtype.yaml
new file mode 100644 (file)
index 0000000..fa9024f
--- /dev/null
@@ -0,0 +1,34 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.4 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_LIB64
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=LIB64
+# RUN: lld -flavor darwin -arch x86_64 -dylib -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=DYLIB
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            start
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+
+...
+
+# NO_LIB64: MH_MAGIC_64  X86_64        ALL 0x00     EXECUTE
+# LIB64: MH_MAGIC_64  X86_64        ALL LIB64     EXECUTE
+# DYLIB: MH_MAGIC_64 X86_64 ALL 0x00 DYLIB
diff --git a/test/mach-o/mh_bundle_header.yaml b/test/mach-o/mh_bundle_header.yaml
new file mode 100644 (file)
index 0000000..d1b7d9a
--- /dev/null
@@ -0,0 +1,54 @@
+# RUN: lld -flavor darwin -arch x86_64  %s -bundle -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64  %s -bundle -dead_strip -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s
+#
+# Test that __mh_bundle_header symbol is available for bundles
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _d
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000008
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_NO_DEAD_STRIP ]
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __mh_bundle_header
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK: __mh_bundle_header
+# CHECK:      _foo
diff --git a/test/mach-o/mh_dylib_header.yaml b/test/mach-o/mh_dylib_header.yaml
new file mode 100644 (file)
index 0000000..8222063
--- /dev/null
@@ -0,0 +1,53 @@
+# RUN: lld -flavor darwin -arch x86_64  %s -dylib -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that __mh_dylib_header symbol is available for dylibs
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000008
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _d
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000008
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __mh_dylib_header
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+
+...
+
+# CHECK_NOT:   __mh_dylib_header
+# CHECK:      _foo
diff --git a/test/mach-o/objc-category-list-atom.yaml b/test/mach-o/objc-category-list-atom.yaml
new file mode 100644 (file)
index 0000000..93974a6
--- /dev/null
@@ -0,0 +1,70 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_catlist
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    alignment:       8
+    address:         0x00000000000003F8
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+undefined-symbols:
+  - name:            __category1
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __category2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# Make sure we atomize the category list section by pointer sized atoms.
+
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:
+# CHECK:   - type:            objc-category-list
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     alignment:       8
+# CHECK:     references:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          __category2
+# CHECK:   - type:            objc-category-list
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:     merge:           by-content
+# CHECK:     alignment:       8
+# CHECK:     references:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          __category1
+# CHECK: undefined-atoms:
+# CHECK:   - name:            __category1
+# CHECK:   - name:            __category2
+# CHECK: ...
diff --git a/test/mach-o/objc-image-info-host-vs-simulator.yaml b/test/mach-o/objc-image-info-host-vs-simulator.yaml
new file mode 100644 (file)
index 0000000..f836a74
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+# The file is built for the host, but the objc image info flags are for
+# the simulator.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: {{.*}} cannot be linked.  It contains ObjC built for the simulator while we are linking a non-simulator target
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-invalid-size.yaml b/test/mach-o/objc-image-info-invalid-size.yaml
new file mode 100644 (file)
index 0000000..47fce88
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: error: __DATA/__objc_imageinfo in file {{.*}} should be 8 bytes in size
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-invalid-version.yaml b/test/mach-o/objc-image-info-invalid-version.yaml
new file mode 100644 (file)
index 0000000..04d62e9
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: error: __DATA/__objc_imageinfo in file {{.*}} should have version=0
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-mismatched-swift-version.yaml b/test/mach-o/objc-image-info-mismatched-swift-version.yaml
new file mode 100644 (file)
index 0000000..efb7c31
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/swift-version-1.yaml 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00 ]
+...
+
+# CHECK: different swift versions
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-pass-output.yaml b/test/mach-o/objc-image-info-pass-output.yaml
new file mode 100644 (file)
index 0000000..7fc95a8
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+
+# Make sure that we have an objc image info in the output.  It should have
+# been generated by the objc pass.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00 ]
+...
+
+# CHECK: --- !native
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:
+# CHECK:   - scope:           hidden
+# CHECK:     type:            objc-image-info
+# CHECK:     content:         [ 00, 00, 00, 00, 20, 02, 00, 00 ]
+# CHECK:     alignment:       4
+# CHECK: ...
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-simulator-vs-host.yaml b/test/mach-o/objc-image-info-simulator-vs-host.yaml
new file mode 100644 (file)
index 0000000..c4f9bd5
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: not lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+# The file is built for the simulator, but the objc image info flags are for
+# the host.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: {{.*}} cannot be linked.  It contains ObjC built for a non-simulator target while we are linking a simulator target
\ No newline at end of file
diff --git a/test/mach-o/objc-image-info-unsupported-gc.yaml b/test/mach-o/objc-image-info-unsupported-gc.yaml
new file mode 100644 (file)
index 0000000..9f98369
--- /dev/null
@@ -0,0 +1,20 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 ]
+...
+
+# CHECK: error: __DATA/__objc_imageinfo in file {{.*}} uses GC. This is not supported
\ No newline at end of file
diff --git a/test/mach-o/objc_export_list.yaml b/test/mach-o/objc_export_list.yaml
new file mode 100644 (file)
index 0000000..a2fcfa2
--- /dev/null
@@ -0,0 +1,63 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t \
+# RUN:     -exported_symbol .objc_class_name_Foo %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that exported objc classes can be specificed using old naming
+# (.e.g .objc_class_name_Foo instead of _OBJC_CLASS_$_Foo)
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __DATA
+    section:         __objc_data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000030
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000028
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            '_OBJC_CLASS_$_Foo'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            '_OBJC_METACLASS_$_Foo'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000028
+...
+
+# CHECK:  (__DATA,__objc_data) external _OBJC_CLASS_$_Foo
+# CHECK:  (__DATA,__objc_data) external _OBJC_METACLASS_$_Foo
diff --git a/test/mach-o/order_file-basic.yaml b/test/mach-o/order_file-basic.yaml
new file mode 100644 (file)
index 0000000..f4d29fa
--- /dev/null
@@ -0,0 +1,75 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \
+# RUN:     -order_file %p/Inputs/order_file-basic.order \
+# RUN:     -force_load %p/Inputs/libfoo.a -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test -order_file
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3, 0xC3, 0xC3, 0xC3 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000014
+    content:         [ 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+                       0x07, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _data1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _data2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000018
+  - name:            _data3
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x000000000000001C
+  - name:            _func1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _func2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _func3
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000002
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000003
+...
+
+
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _func2
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _foo
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _func1
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _func3
+# CHECK:       {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK:       {{[0-9a-f]+}} (__DATA,__data) external _data3
+# CHECK:       {{[0-9a-f]+}} (__DATA,__data) external _data1
+# CHECK:       {{[0-9a-f]+}} (__DATA,__data) external _data2
+
diff --git a/test/mach-o/parse-aliases.yaml b/test/mach-o/parse-aliases.yaml
new file mode 100644 (file)
index 0000000..54da2d6
--- /dev/null
@@ -0,0 +1,90 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test multiple labels to same address parse into aliases.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3 ]
+local-symbols:
+  - name:            _pad
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _myStaticAlias1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myStaticAlias3
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myStaticAlias2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+global-symbols:
+  - name:            _myGlobalFunc1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalFunc2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalFunc3
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myHiddenAlias1
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myHiddenAlias2
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myHiddenAlias3
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000001
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _pad
+# CHECK:     scope:           global
+# CHECK:     content:         [ CC ]
+# CHECK:   - name:            _myStaticAlias1
+# CHECK:   - name:            _myStaticAlias2
+# CHECK:   - name:            _myStaticAlias3
+# CHECK:   - name:            _myHiddenAlias1
+# CHECK:     scope:           hidden
+# CHECK:   - name:            _myHiddenAlias2
+# CHECK:     scope:           hidden
+# CHECK:   - name:            _myHiddenAlias3
+# CHECK:     scope:           hidden
+# CHECK:   - name:            _myGlobalFunc1
+# CHECK:     scope:           global
+# CHECK:   - name:            _myGlobalFunc2
+# CHECK:     scope:           global
+# CHECK:   - name:            _myGlobalFunc3
+# CHECK:     scope:           global
+# CHECK:     content:         [ C3 ]
diff --git a/test/mach-o/parse-arm-relocs.yaml b/test/mach-o/parse-arm-relocs.yaml
new file mode 100644 (file)
index 0000000..abeb3dd
--- /dev/null
@@ -0,0 +1,818 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t   | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2  | FileCheck %s
+#
+# Test parsing of armv7 relocations.
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xF0, 0x4E, 0xF8, 0x00, 0xF0, 0x4E, 0xF8,
+                       0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF,
+                       0xFF, 0xF7, 0xF6, 0xBF, 0x40, 0xF2, 0x72, 0x01,
+                       0xC0, 0xF2, 0x00, 0x01, 0x40, 0xF2, 0x7A, 0x02,
+                       0xC0, 0xF2, 0x00, 0x02, 0x40, 0xF2, 0x29, 0x01,
+                       0xC0, 0xF2, 0x00, 0x01, 0x79, 0x44, 0x40, 0xF2,
+                       0xA0, 0x03, 0xC0, 0xF2, 0x00, 0x03, 0x40, 0xF2,
+                       0xA8, 0x04, 0xC0, 0xF2, 0x00, 0x04, 0x40, 0xF2,
+                       0x57, 0x03, 0xC0, 0xF2, 0x00, 0x03, 0x40, 0xF2,
+                       0x00, 0x05, 0xC0, 0xF2, 0x00, 0x05, 0x40, 0xF2,
+                       0x08, 0x06, 0xC0, 0xF2, 0x00, 0x06, 0xC0, 0x46,
+                       0x10, 0x00, 0x00, 0xEB, 0x10, 0x00, 0x00, 0xEB,
+                       0xE6, 0xFF, 0xFF, 0xEB, 0xE6, 0xFF, 0xFF, 0xEB,
+                       0xE4, 0xFF, 0xFF, 0xEA, 0x20, 0x10, 0x00, 0xE3,
+                       0x00, 0x10, 0x40, 0xE3, 0x28, 0x20, 0x00, 0xE3,
+                       0x00, 0x20, 0x40, 0xE3, 0x0F, 0x10, 0x81, 0xE0,
+                       0xA0, 0x30, 0x00, 0xE3, 0x00, 0x30, 0x40, 0xE3,
+                       0xA8, 0x40, 0x00, 0xE3, 0x00, 0x40, 0x40, 0xE3,
+                       0x00, 0x50, 0x00, 0xE3, 0x00, 0x50, 0x40, 0xE3,
+                       0x08, 0x60, 0x00, 0xE3, 0x00, 0x60, 0x40, 0xE3 ]
+    relocations:
+      - offset:          0x0000009C
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000098
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000094
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000090
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000008C
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x000000A8
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000088
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000084
+        type:            ARM_RELOC_HALF
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x000000A0
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000080
+        type:            ARM_RELOC_HALF
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000078
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000028
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000074
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000070
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          1
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000020
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          1
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x0000006C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          0
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          0
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000068
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000064
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000060
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x0000005C
+        scattered:       true
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        value:           0x000000A0
+      - offset:          0x00000058
+        type:            ARM_RELOC_BR24
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x00000052
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000004E
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000004A
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000046
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000042
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000057
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000003E
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000003A
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x000000A8
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000036
+        scattered:       true
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000032
+        type:            ARM_RELOC_HALF
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x000000A0
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x0000002E
+        type:            ARM_RELOC_HALF
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000000
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16777215
+      - offset:          0x00000028
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x00000056
+      - offset:          0x00000028
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000024
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000056
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000020
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x0000007A
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000018
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          3
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000072
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          3
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000014
+        scattered:       true
+        type:            ARM_RELOC_HALF_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x000000A0
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000002E
+      - offset:          0x00000010
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x0000000C
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000004
+        scattered:       true
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        value:           0x000000A0
+      - offset:          0x00000000
+        type:            ARM_THUMB_RELOC_BR22
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x00000000000000A0
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0xA4, 0xFF, 0xFF, 0xFF,
+                       0xA4, 0xFF, 0xFF, 0xFF, 0x45, 0xFF, 0xFF, 0xFF,
+                       0x45, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000020
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000C0
+      - offset:          0x0000001C
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000BC
+      - offset:          0x00000018
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000058
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000B8
+      - offset:          0x00000014
+        scattered:       true
+        type:            ARM_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000058
+      - offset:          0x00000000
+        scattered:       true
+        type:            ARM_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x000000B4
+      - offset:          0x00000010
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x0000000C
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          4
+      - offset:          0x00000008
+        scattered:       true
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000004
+        type:            ARM_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+local-symbols:
+  - name:            _foo_thumb
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _x
+    type:            N_SECT
+    sect:            2
+    value:           0x00000000000000A0
+  - name:            _t1
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000056
+  - name:            _foo_arm
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000058
+undefined-symbols:
+  - name:            _undef
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:  defined-atoms:
+# CHECK:    - name:            _x
+# CHECK:      type:            data
+# CHECK:      references:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          4
+# CHECK:          target:          _foo_thumb
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          8
+# CHECK:          target:          _foo_thumb
+# CHECK:          addend:          4
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          12
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          16
+# CHECK:          target:          _undef
+# CHECK:          addend:          4
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          20
+# CHECK:          target:          _foo_arm
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          24
+# CHECK:          target:          _foo_arm
+# CHECK:          addend:          4
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          28
+# CHECK:          target:          _foo_thumb
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            delta32
+# CHECK:          offset:          32
+# CHECK:          target:          _foo_thumb
+# CHECK:          addend:          4
+# CHECK:    - name:            _foo_thumb
+# CHECK:      references:
+# CHECK:        - kind:            modeThumbCode
+# CHECK:          offset:          0
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          0
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          4
+# CHECK:          target:          _x
+# CHECK:          addend:          4
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          8
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_bl22
+# CHECK:          offset:          12
+# CHECK:          target:          _undef
+# CHECK:          addend:          4
+# CHECK:        - kind:            thumb_b22
+# CHECK:          offset:          16
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw_funcRel
+# CHECK:          offset:          20
+# CHECK:          target:          _x
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movt_funcRel
+# CHECK:          offset:          24
+# CHECK:          target:          _x
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movw_funcRel
+# CHECK:          offset:          28
+# CHECK:          target:          _x
+# CHECK:          addend:          -38
+# CHECK:        - kind:            thumb_movt_funcRel
+# CHECK:          offset:          32
+# CHECK:          target:          _x
+# CHECK:          addend:          -38
+# CHECK:        - kind:            thumb_movw_funcRel
+# CHECK:          offset:          36
+# CHECK:          target:          _t1
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movt_funcRel
+# CHECK:          offset:          40
+# CHECK:          target:          _t1
+# CHECK:          addend:          -46
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          46
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          50
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          54
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          58
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          62
+# CHECK:          target:          _t1
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          66
+# CHECK:          target:          _t1
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          70
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          74
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            thumb_movw
+# CHECK:          offset:          78
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:        - kind:            thumb_movt
+# CHECK:          offset:          82
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:    - name:            _t1
+# CHECK:      content:         [ C0, 46 ]
+# CHECK:      references:
+# CHECK:        - kind:            modeThumbCode
+# CHECK:          offset:          0
+# CHECK:    - name:            _foo_arm
+# CHECK:      references:
+# CHECK-NOT:    - kind:            modeThumbCode
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          0
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          4
+# CHECK:          target:          _x
+# CHECK:          addend:          4
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          8
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_bl24
+# CHECK:          offset:          12
+# CHECK:          target:          _undef
+# CHECK:          addend:          4
+# CHECK:        - kind:            arm_b24
+# CHECK:          offset:          16
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movw_funcRel
+# CHECK:          offset:          20
+# CHECK:          target:          _x
+# CHECK:          addend:          -40
+# CHECK:        - kind:            arm_movt_funcRel
+# CHECK:          offset:          24
+# CHECK:          target:          _x
+# CHECK:          addend:          -40
+# CHECK:        - kind:            arm_movw_funcRel
+# CHECK:          offset:          28
+# CHECK:          target:          _x
+# CHECK:          addend:          -32
+# CHECK:        - kind:            arm_movt_funcRel
+# CHECK:          offset:          32
+# CHECK:          target:          _x
+# CHECK:          addend:          -32
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          40
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          44
+# CHECK:          target:          _x
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          48
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          52
+# CHECK:          target:          _x
+# CHECK:          addend:          8
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          56
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          60
+# CHECK:          target:          _undef
+# CHECK-NOT:      addend:
+# CHECK:        - kind:            arm_movw
+# CHECK:          offset:          64
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:        - kind:            arm_movt
+# CHECK:          offset:          68
+# CHECK:          target:          _undef
+# CHECK:          addend:          8
+# CHECK:  undefined-atoms:
+# CHECK:    - name:            _undef
+
+
+
+
+#      .align  2
+#      .code   16
+#  .thumb_func _foo_thumb
+#_foo_thumb:
+#  bl    _x
+#  bl    _x+4
+#  bl    _undef
+#  bl    _undef+4
+#  b     _undef
+#  movw        r1, :lower16:(_x-L1)
+#  movt        r1, :upper16:(_x-L1)
+#  movw        r2, :lower16:(_x+8-L1)
+#  movt        r2, :upper16:(_x+8-L1)
+#  movw        r1, :lower16:(_t1-L1)
+#  movt        r1, :upper16:(_t1-L1)
+#      add     r1, pc
+#L1:
+#      movw    r3, :lower16:_x
+#      movt    r3, :upper16:_x
+#      movw    r4, :lower16:_x+8
+#      movt    r4, :upper16:_x+8
+#      movw    r3, :lower16:_t1
+#      movt    r3, :upper16:_t1
+#      movw    r5, :lower16:_undef
+#      movt    r5, :upper16:_undef
+#      movw    r6, :lower16:_undef+8
+#      movt    r6, :upper16:_undef+8
+#
+#  .thumb_func _t1
+#_t1:
+#  nop
+#
+#
+#      .code   32
+#  .align 2
+#_foo_arm:
+#  bl    _x
+#  bl    _x+4
+#  bl    _undef
+#  bl    _undef+4
+#  b     _undef
+#  movw        r1, :lower16:(_x-L2)
+#  movt        r1, :upper16:(_x-L2)
+#  movw        r2, :lower16:(_x+8-L2)
+#  movt        r2, :upper16:(_x+8-L2)
+#      add     r1, pc
+#L2:
+#      movw    r3, :lower16:_x
+#      movt    r3, :upper16:_x
+#      movw    r4, :lower16:_x+8
+#      movt    r4, :upper16:_x+8
+#      movw    r5, :lower16:_undef
+#      movt    r5, :upper16:_undef
+#      movw    r6, :lower16:_undef+8
+#      movt    r6, :upper16:_undef+8
+#
+#
+#  .data
+#_x:  .long 0
+#    .long _foo_thumb
+#    .long _foo_thumb+4
+#    .long _undef
+#    .long _undef+4
+#    .long _foo_arm - .
+#    .long _foo_arm+4- .
+#    .long _foo_thumb - .
+#    .long _foo_thumb+4 - .
+#
diff --git a/test/mach-o/parse-cfstring32.yaml b/test/mach-o/parse-cfstring32.yaml
new file mode 100644 (file)
index 0000000..8e746f2
--- /dev/null
@@ -0,0 +1,94 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of mach-o functions.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+                       0x65, 0x72, 0x65, 0x00 ]
+  - segment:         __DATA
+    section:         __cfstring
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000010
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00,
+                       0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000018
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000010
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000008
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+undefined-symbols:
+  - name:            ___CFConstantStringClassReference
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:  - ref-name:        [[STR1:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - ref-name:        [[STR2:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 74, 68, 65, 72, 65, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          0
+# CHECK:          target:          ___CFConstantStringClassReference
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          8
+# CHECK:          target:          [[STR1]]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          0
+# CHECK:          target:          ___CFConstantStringClassReference
+# CHECK:        - kind:            pointer32
+# CHECK:          offset:          8
+# CHECK:          target:          [[STR2]]
+# CHECK:undefined-atoms:
+# CHECK:  - name:            ___CFConstantStringClassReference
diff --git a/test/mach-o/parse-cfstring64.yaml b/test/mach-o/parse-cfstring64.yaml
new file mode 100644 (file)
index 0000000..b90277f
--- /dev/null
@@ -0,0 +1,108 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of CFString constants.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+                       0x65, 0x72, 0x65, 0x00 ]
+  - segment:         __DATA
+    section:         __cfstring
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       4
+    address:         0x0000000000000010
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000030
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+      - offset:          0x00000020
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+local-symbols:
+  - name:            Lstr1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            Lstr2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000006
+undefined-symbols:
+  - name:            ___CFConstantStringClassReference
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:defined-atoms:
+# CHECK:  - ref-name:        L000
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - ref-name:        L001
+# CHECK:    scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 74, 68, 65, 72, 65, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          0
+# CHECK:        target:          ___CFConstantStringClassReference
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          16
+# CHECK:        target:          L000
+# CHECK:  - scope:           hidden
+# CHECK:    type:            cfstring
+# CHECK:    merge:           by-content
+# CHECK:    references:
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          0
+# CHECK:        target:          ___CFConstantStringClassReference
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          16
+# CHECK:        target:          L001
+# CHECK:undefined-atoms:
+# CHECK:  - name:            ___CFConstantStringClassReference
+
diff --git a/test/mach-o/parse-compact-unwind32.yaml b/test/mach-o/parse-compact-unwind32.yaml
new file mode 100644 (file)
index 0000000..ff613f0
--- /dev/null
@@ -0,0 +1,72 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of __LD/__compact_unwind (compact unwind) section.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0xB8, 0x0A, 0x00, 0x00, 0x00,
+                       0x5D, 0xC3, 0x55, 0x89, 0xE5, 0xB8, 0x0A, 0x00,
+                       0x00, 0x00, 0x5D, 0xC3 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x000000000000001C
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+                       0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000014
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000A
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 00, 00, 00, 00, 0A, 00, 00, 00, 00, 00, 00, 01,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 10, 00, 00, 00, 0A, 00, 00, 00, 00, 00, 00, 01,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - name:            __Z3foov
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+# CHECK:   - name:            __Z3barv
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+
diff --git a/test/mach-o/parse-compact-unwind64.yaml b/test/mach-o/parse-compact-unwind64.yaml
new file mode 100644 (file)
index 0000000..af89674
--- /dev/null
@@ -0,0 +1,76 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of __LD/__compact_unwind (compact unwind) section.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x0A, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
+                       0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000020
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000020
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000B
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 0B, 00, 00, 00,
+# CHECK:                        00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - type:            compact-unwind
+# CHECK:     content:         [ 10, 00, 00, 00, 00, 00, 00, 00, 0B, 00, 00, 00,
+# CHECK:                        00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - name:            __Z3barv
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+# CHECK:   - name:            __Z3foov
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
diff --git a/test/mach-o/parse-data-in-code-armv7.yaml b/test/mach-o/parse-data-in-code-armv7.yaml
new file mode 100644 (file)
index 0000000..163cb18
--- /dev/null
@@ -0,0 +1,157 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t  | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2  | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -dylib %s -o %t3.dylib %p/Inputs/armv7/libSystem.yaml \
+# RUN:   && llvm-objdump -macho -private-headers %t3.dylib | FileCheck --check-prefix=CHECK2 %s
+#
+# Test parsing LC_DATA_IN_CODE
+#
+#
+
+--- !mach-o
+arch:            armv7
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0x00, 0xBF, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                       0x03, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0xBF,
+                       0x00, 0xF0, 0x20, 0xE3, 0x0A, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
+                       0x0D, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3 ]
+local-symbols:
+  - name:            _foo_thumb
+    type:            N_SECT
+    sect:            1
+    desc:            [ N_ARM_THUMB_DEF ]
+    value:           0x0000000000000000
+  - name:            _foo_arm
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000018
+dataInCode:
+  - offset:          0x00000004
+    length:          0x0004
+    kind:            DICE_KIND_DATA
+  - offset:          0x00000008
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE32
+  - offset:          0x0000000C
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE16
+  - offset:          0x00000010
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE8
+  - offset:          0x0000001C
+    length:          0x0004
+    kind:            DICE_KIND_DATA
+  - offset:          0x00000020
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE32
+  - offset:          0x00000024
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE16
+  - offset:          0x00000028
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE8
+...
+
+
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _foo_thumb
+# CHECK:     references:
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          0
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          4
+# CHECK:         addend:          1
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          8
+# CHECK:         addend:          4
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          12
+# CHECK:         addend:          3
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          16
+# CHECK:         addend:          2
+# CHECK:       - kind:            modeThumbCode
+# CHECK:         offset:          20
+# CHECK:   - name:            _foo_arm
+# CHECK:     references:
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          4
+# CHECK:         addend:          1
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          8
+# CHECK:         addend:          4
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          12
+# CHECK:         addend:          3
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          16
+# CHECK:         addend:          2
+# CHECK:       - kind:            modeArmCode
+# CHECK:         offset:          20
+
+
+# CHECK2:      cmd LC_DATA_IN_CODE
+# CHECK2:  cmdsize 16
+# CHECK2: datasize 64
+
+
+#      .code   16
+#  .thumb_func _foo_thumb
+#_foo_thumb:
+# nop
+# nop
+#
+#      .data_region
+#  .long 0
+#      .end_data_region
+#
+#      .data_region jt32
+#  .long 1
+#      .end_data_region
+#
+#      .data_region jt16
+#  .long 2
+#      .end_data_region
+#
+#      .data_region jt8
+#  .long 3
+#      .end_data_region
+#
+#  nop
+#  nop
+#
+#
+#
+#      .code   32
+#  .align 2
+#_foo_arm:
+#  nop
+#
+#      .data_region
+#  .long 10
+#      .end_data_region
+#
+#      .data_region jt32
+#  .long 11
+#      .end_data_region
+#
+#      .data_region jt16
+#  .long 12
+#      .end_data_region
+#
+#      .data_region jt8
+#  .long 13
+#      .end_data_region
+#
+#  nop
+#
diff --git a/test/mach-o/parse-data-in-code-x86.yaml b/test/mach-o/parse-data-in-code-x86.yaml
new file mode 100644 (file)
index 0000000..4393444
--- /dev/null
@@ -0,0 +1,77 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s \
+# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2  | FileCheck %s
+#
+# Test parsing LC_DATA_IN_CODE
+#
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x90, 0x90, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
+                       0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x03, 0x00,
+                       0x00, 0x00 ]
+local-symbols:
+  - name:            _func1
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _func2
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+dataInCode:
+  - offset:          0x00000002
+    length:          0x0008
+    kind:            DICE_KIND_JUMP_TABLE32
+  - offset:          0x0000000E
+    length:          0x0004
+    kind:            DICE_KIND_JUMP_TABLE32
+...
+
+
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _func1
+# CHECK:     references:
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          2
+# CHECK:         addend:          4
+# CHECK:       - kind:            modeCode
+# CHECK:         offset:          10
+# CHECK:   - name:            _func2
+# CHECK:     references:
+# CHECK:       - kind:            modeData
+# CHECK:         offset:          3
+# CHECK:         addend:          4
+# CHECK-NOT:   - kind:            modeData
+
+
+
+
+#
+#_func1:
+#  nop
+#  nop
+#  .data_region jt32
+#  .long 1
+#  .long 2
+#  .end_data_region
+#  nop
+#
+#
+# _func2:
+#  nop
+#  nop
+#  nop
+#  .data_region jt32
+#  .long 3
+#  .end_data_region
+#
diff --git a/test/mach-o/parse-data-relocs-arm64.yaml b/test/mach-o/parse-data-relocs-arm64.yaml
new file mode 100644 (file)
index 0000000..0edd646
--- /dev/null
@@ -0,0 +1,244 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of arm64 data relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xC0, 0x03, 0x5F, 0xD6 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000004
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xC0, 0xFF, 0xFF, 0xFF, 0xBE, 0xFF, 0xFF, 0xFF,
+                       0xB0, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000050
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000004C
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x0000004C
+        type:            ARM64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            ARM64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000040
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000038
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000030
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000030
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000028
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000028
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000020
+        type:            ARM64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000018
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000008
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+local-symbols:
+  - name:            _v1
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000000C
+global-symbols:
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        L000
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:   - name:            _v1
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 08, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, 00, 00, 00, 00, E0, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, DC, FF, FF, FF, FF, FF, FF, FF,
+# CHECK:                        {{..}}, {{..}}, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00, C0, FF, FF, FF, BE, FF, FF, FF,
+# CHECK:                        {{B0|B8}}, {{..}}, FF, FF ]
+# CHECK:     references:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          0
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          8
+# CHECK:         target:          _foo
+# CHECK:         addend:          8
+# CHECK:       - kind:            pointer64ToGOT
+# CHECK:         offset:          16
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            delta64
+# CHECK:         offset:          24
+# CHECK:         target:          _foo
+# CHECK:         addend:          24
+# CHECK:       - kind:            delta64
+# CHECK:         offset:          32
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            delta64
+# CHECK:         offset:          40
+# CHECK:         target:          _foo
+# CHECK:         addend:          4
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          48
+# CHECK:         target:          L000
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer64
+# CHECK:         offset:          56
+# CHECK:         target:          _foo
+# CHECK:         addend:          4
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          64
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          68
+# CHECK:         target:          _foo
+# CHECK:         addend:          2
+# CHECK:       - kind:            delta32ToGOT
+# CHECK:         offset:          72
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:  - name:            _bar
+# CHECK:    scope:           global
+# CHECK:    content:         [ C0, 03, 5F, D6 ]
+# CHECK:    alignment:       4
+# CHECK: undefined-atoms:
+# CHECK:   - name:            _foo
+
+# .subsections_via_symbols
+# .text
+# .globl_foo
+# .align2
+# _foo:
+# ret
+#  .data
+#Lanon:
+#  .quad     0
+#_v1:
+# .quad   _foo
+# .quad   _foo + 8
+#  .quad   _foo@GOT
+#  .quad   _foo + 24 - .
+#  .quad   _foo - .
+#  .quad   _foo + 4 - .
+#  .quad   Lanon
+#  .quad   Lanon + 4
+#  .long   _foo - .
+#  .long   _foo +2 - .
+# .long   _foo@GOT - .
+
diff --git a/test/mach-o/parse-data-relocs-x86_64.yaml b/test/mach-o/parse-data-relocs-x86_64.yaml
new file mode 100644 (file)
index 0000000..6b5bb4b
--- /dev/null
@@ -0,0 +1,372 @@
+
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \
+# RUN: && lld -flavor darwin -arch x86_64 %t -r -print_atoms -o %t2  | FileCheck %s
+#
+# Test parsing and writing of x86_64 data relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_foo:
+#  ret
+#
+#_bar:
+#  ret
+#
+#  .section __DATA,__custom
+#L1:
+#  .quad 0
+#
+#  .data
+#_d:
+#  .quad   _foo
+#  .quad   _foo+4
+#  .quad   _foo - .
+#  .quad   L1
+#  .quad   L1 + 2
+#  .quad   _foo - .
+#  .quad   _foo + 4 - .
+#  .quad   L1 - .
+#  .long   _foo - .
+#  .long   _foo + 4 - .
+#  .long   L1 - .
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xC3, 0xC3 ]
+  - segment:         __DATA
+    section:         __custom
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000002
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000000A
+    content:         [
+#  .quad   _foo
+# No addend is needed here as we are referencing _foo directly and that is
+# encoded entirely in the X86_64_RELOC_UNSIGNED
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   _foo+4
+# Addend of 4 is needed here as we are referencing _foo from the
+# X86_64_RELOC_UNSIGNED, then the addend gives us 4 more.
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   _foo - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -16 because that is the offset from here back
+# to _d.
+                       0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .quad   . - _foo
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -16 because that is the offset from here back
+# to _d.
+                       0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   L1
+# This is a X86_64_RELOC_UNSIGNED without extern set.
+# In this case, we encode the section number for L1 in the relocation, and
+# the addend here is the absolute address of the location in that section
+# we want to reference.
+                       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   L1 + 2
+# This is a X86_64_RELOC_UNSIGNED without extern set.
+# In this case, we encode the section number for L1 in the relocation, and
+# the addend here is the absolute address of the location in that section
+# we want to reference.  We have a 4 because the section is at address 2
+# and we want an offset of 2 from there.
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#  .quad   _foo - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -40 because that is the offset from here back
+# to _d.
+                       0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .quad   _foo + 4 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -52.  It would have been -56 because that
+# would take us from the address of this relocation back to _d.  But as
+# we also add 4 for the offset, we get -52.
+                       0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .quad   L1 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned does not have extern set, so the relocation
+# number is the section number for L1.
+# Note the addend here is -62. Of that, -64 would be the offset from
+# this location from _d.  The remaining 2 is the absolute address
+# of L1.
+                       0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+#  .long   _foo - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -72 because that is the offset from here back
+# to _d.
+                       0xB8, 0xFF, 0xFF, 0xFF,
+#  .long   . - _foo
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -76 because that is the offset from here back
+# to _d.
+                       0xB4, 0xFF, 0xFF, 0xFF,
+#  .long   _foo + 4 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned references _foo.
+# Note the addend here is -76.  It would have been -80 because that
+# would take us from the address of this relocation back to _d.  But as
+# we also add 4 for the offset, we get -76.
+                       0xB4, 0xFF, 0xFF, 0xFF,
+#  .long   L1 - .
+# This is the pair X86_64_RELOC_SUBTRACTOR and X86_64_RELOC_UNSIGNED.
+# The subtractor references _d which is the first nonlocal label in this
+# section.  The unsigned does not have extern set, so the relocation
+# number is the section number for L1.
+# Note the addend here is -82. Of that, -84 would be the offset from
+# this location from _d.  The remaining 2 is the absolute address
+# of L1.
+                       0xAE, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000054
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000054
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000050
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000050
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x0000004C
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x0000004C
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000048
+        type:            X86_64_RELOC_UNSIGNED
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000040
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000040
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000038
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000038
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000030
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000030
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000028
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000020
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000018
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000018
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            X86_64_RELOC_SUBTRACTOR
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+local-symbols:
+  - name:            _foo
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _bar
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _d
+    type:            N_SECT
+    sect:            3
+    value:           0x000000000000000A
+page-size:       0x00000000
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - name:            _d
+# CHECK:    type:            data
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00,
+# CHECK:                       00, 00, 00, 00, F0, FF, FF, FF, FF, FF, FF, FF,
+# CHECK:                       18, 00, 00, 00, 00, 00, 00, 00, {{..}}, {{..}}, 00, 00,
+# CHECK:                       00, 00, 00, 00, {{..}}, {{..}}, 00, 00, 00, 00, 00, 00,
+# CHECK:                       D0, FF, FF, FF, FF, FF, FF, FF, CC, FF, FF, FF,
+# CHECK:                       FF, FF, FF, FF, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}},
+# CHECK:                       B8, FF, FF, FF, B4, FF, FF, FF, B4, FF, FF, FF,
+# CHECK:                       {{..}}, {{..}}, {{..}}, {{..}} ]
+# CHECK:    dead-strip:      never
+# CHECK:    references:
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          0
+# CHECK:        target:          _foo
+# CHECK:      - kind:            pointer64
+# CHECK:        offset:          8
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            delta64
+# CHECK:        offset:          16
+# CHECK:        target:          _foo
+# CHECK:      - kind:            negDelta64
+# CHECK:        offset:          24
+# CHECK:        target:          _foo
+# CHECK:      - kind:            pointer64Anon
+# CHECK:        offset:          32
+# CHECK:        target:          L003
+# CHECK:      - kind:            pointer64Anon
+# CHECK:        offset:          40
+# CHECK:        target:          L003
+# CHECK:        addend:          2
+# CHECK:      - kind:            delta64
+# CHECK:        offset:          48
+# CHECK:        target:          _foo
+# CHECK:      - kind:            delta64
+# CHECK:        offset:          56
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            delta64Anon
+# CHECK:        offset:          64
+# CHECK:        target:          L003
+# CHECK:      - kind:            delta32
+# CHECK:        offset:          72
+# CHECK:        target:          _foo
+# CHECK:      - kind:            negDelta32
+# CHECK:        offset:          76
+# CHECK:        target:          _foo
+# CHECK:      - kind:            delta32
+# CHECK:        offset:          80
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            delta32Anon
+# CHECK:        offset:          84
+# CHECK:        target:          L003
+# CHECK:  - name:            _foo
+# CHECK:    content:         [ C3 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - name:            _bar
+# CHECK:    content:         [ C3 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - ref-name:        L003
+# CHECK:    type:            unknown
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    section-choice:  custom-required
+# CHECK:    section-name:    __DATA/__custom
+# CHECK:    dead-strip:      never
+
diff --git a/test/mach-o/parse-data.yaml b/test/mach-o/parse-data.yaml
new file mode 100644 (file)
index 0000000..3b422e0
--- /dev/null
@@ -0,0 +1,119 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of mach-o data symbols.
+#
+# long a = 0x0807060504030201;
+# int b = 0x14131211;
+# int c = 0x24232221;
+# static int s1;
+# static int s2 = 0x34333231;
+#
+#
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000000
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24,
+                       0x31, 0x32, 0x33, 0x34, 0x41, 0x42, 0x43, 0x44 ]
+  - segment:         __CUST
+    section:         __custom
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000018
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ]
+  - segment:         __DATA
+    section:         __bss
+    type:            S_ZEROFILL
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000020
+    size:            4
+local-symbols:
+  - name:            _s1
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000020
+  - name:            _s2
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000010
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000008
+  - name:            _c
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+  - name:            _cWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000014
+  - name:            _kustom
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000018
+...
+
+# CHECK: defined-atoms:
+
+# CHECK:   - name:            _a
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+
+# CHECK:   - name:            _b
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 11, 12, 13, 14 ]
+
+# CHECK:   - name:            _c
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 21, 22, 23, 24 ]
+
+# CHECK:   - name:            _s2
+# CHECK:     type:            data
+# CHECK:     content:         [ 31, 32, 33, 34 ]
+
+# CHECK:   - name:            _cWeak
+# CHECK:     scope:           global
+# CHECK:     type:            data
+# CHECK:     content:         [ 41, 42, 43, 44 ]
+# CHECK:     merge:           as-weak
+
+# CHECK:   - name:            _s1
+# CHECK:     type:            zero-fill
+# CHECK:     size:            4
+
+# CHECK:   - name:            _kustom
+# CHECK:     scope:           global
+# CHECK:     type:            unknown
+# CHECK:     content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __CUST/__custom
+
diff --git a/test/mach-o/parse-eh-frame-relocs-x86_64.yaml b/test/mach-o/parse-eh-frame-relocs-x86_64.yaml
new file mode 100644 (file)
index 0000000..b009cbc
--- /dev/null
@@ -0,0 +1,176 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of x86_64 __eh_frame (dwarf unwind) relocations.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00,
+                       0x00, 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00,
+                       0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x66, 0x2E,
+                       0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x48, 0x89, 0xC7, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00, 0x00, 0x00,
+                       0x00 ]
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       4
+    address:         0x000000000000004C
+    content:         [ 0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A,
+                       0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00,
+                       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xFF, 0x9B, 0xA2, 0x80, 0x80, 0x00, 0x03, 0x1A,
+                       0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x0B, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x00,
+                       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000100
+    content:         [ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78,
+                       0x10, 0x07, 0x9B, 0x04, 0x00, 0x00, 0x00, 0x10,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x2C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+                       0xD8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0xB0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x2C, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
+                       0x98, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0xCB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000013
+        type:            X86_64_RELOC_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          8
+local-symbols:
+  - name:            GCC_except_table0
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000004C
+  - name:            GCC_except_table2
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000074
+global-symbols:
+  - name:            _catchMyException1
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _catchMyException2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000030
+  - name:            _bar
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000020
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_begin_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_end_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___gxx_personality_v0
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# Check that LSDA fields are fixed up correctly, even when there are multiple
+# CIEs involved.
+#
+# (1) Check that we can relocate an LSDA at all. Requires correct interpretation
+#     of augmentation data strings in CIEs and augmentation data fields of FDEs.
+#
+# CHECK:       - type:            unwind-cfi
+# CHECK-NOT:   - type:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            negDelta32
+# CHECK-NEXT:        offset:          4
+# CHECK-NEXT:        target:          L002
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          8
+# CHECK-NEXT:        target:          _catchMyException1
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          25
+# CHECK-NEXT:        target:          GCC_except_table0
+#
+# (2) Check that we have an intervening FDE with a different CIE.
+#     If the test fails here then test (3) probably isn't testing what it
+#     should, and this test-case should be updated.
+#
+# CHECK:       - type:            unwind-cfi
+# CHECK-NOT:   - type:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            negDelta32
+# CHECK-NEXT:        offset:          4
+# CHECK-NEXT:        target:          L001
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          8
+# CHECK-NEXT:        target:          _bar
+#
+# (3) Check that we can relocate the LSDA on a second FDE that references the
+#     original CIE from (1). Requires us to match this FDE up with the correct
+#     CIE.
+#
+# CHECK-NEXT:  - type:            unwind-cfi
+# CHECK-NOT:   - type:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            negDelta32
+# CHECK-NEXT:        offset:          4
+# CHECK-NEXT:        target:          L002
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          8
+# CHECK-NEXT:        target:          _catchMyException2
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          25
+# CHECK-NEXT:        target:          GCC_except_table2
diff --git a/test/mach-o/parse-eh-frame-x86-anon.yaml b/test/mach-o/parse-eh-frame-x86-anon.yaml
new file mode 100644 (file)
index 0000000..09b6ba3
--- /dev/null
@@ -0,0 +1,129 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of new __eh_frame (dwarf unwind) section that has no .eh labels
+# and no relocations.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x56, 0x83, 0xEC, 0x14, 0xE8,
+                       0x00, 0x00, 0x00, 0x00, 0x5E, 0xC7, 0x04, 0x24,
+                       0x04, 0x00, 0x00, 0x00, 0xE8, 0xE7, 0xFF, 0xFF,
+                       0xFF, 0xC7, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x8B,
+                       0x8E, 0x38, 0x00, 0x00, 0x00, 0x89, 0x4C, 0x24,
+                       0x04, 0x89, 0x04, 0x24, 0xC7, 0x44, 0x24, 0x08,
+                       0x00, 0x00, 0x00, 0x00, 0xE8, 0xC7, 0xFF, 0xFF,
+                       0xFF, 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8,
+                       0xBC, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000040
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000035
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000021
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000044
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000015
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+  - segment:         __IMPORT
+    section:         __pointers
+    type:            S_NON_LAZY_SYMBOL_POINTERS
+    attributes:      [  ]
+    address:         0x0000000000000044
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+    indirect-syms:   [ 5 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000048
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x7C, 0x08, 0x01,
+                       0x10, 0x0C, 0x05, 0x04, 0x88, 0x01, 0x00, 0x00,
+                       0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x98, 0xFF, 0xFF, 0xFF, 0x39, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x08, 0x84, 0x02, 0x42, 0x0D,
+                       0x04, 0x44, 0x86, 0x03, 0x18, 0x00, 0x00, 0x00,
+                       0x38, 0x00, 0x00, 0x00, 0xB5, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0E, 0x08,
+                       0x84, 0x02, 0x42, 0x0D, 0x04, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000039
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            __ZTIi
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_allocate_exception
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_throw
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[CIE:L[L0-9]+]]
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
+
diff --git a/test/mach-o/parse-eh-frame-x86-labeled.yaml b/test/mach-o/parse-eh-frame-x86-labeled.yaml
new file mode 100644 (file)
index 0000000..5be5abc
--- /dev/null
@@ -0,0 +1,193 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of old __eh_frame (dwarf unwind) section that has .eh labels
+# and relocations.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x56, 0x83, 0xEC, 0x14, 0xE8,
+                       0x00, 0x00, 0x00, 0x00, 0x5E, 0xC7, 0x04, 0x24,
+                       0x04, 0x00, 0x00, 0x00, 0xE8, 0xE7, 0xFF, 0xFF,
+                       0xFF, 0xC7, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x8B,
+                       0x8E, 0x38, 0x00, 0x00, 0x00, 0x89, 0x4C, 0x24,
+                       0x04, 0x89, 0x04, 0x24, 0xC7, 0x44, 0x24, 0x08,
+                       0x00, 0x00, 0x00, 0x00, 0xE8, 0xC7, 0xFF, 0xFF,
+                       0xFF, 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8,
+                       0xBC, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000040
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000035
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          7
+      - offset:          0x00000021
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000044
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000C
+      - offset:          0x00000015
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          6
+  - segment:         __IMPORT
+    section:         __pointers
+    type:            S_NON_LAZY_SYMBOL_POINTERS
+    attributes:      [  ]
+    address:         0x0000000000000044
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+    indirect-syms:   [ 5 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000048
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x7C, 0x08, 0x01,
+                       0x10, 0x0C, 0x05, 0x04, 0x88, 0x01, 0x00, 0x00,
+                       0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x98, 0xFF, 0xFF, 0xFF, 0x39, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x08, 0x84, 0x02, 0x42, 0x0D,
+                       0x04, 0x44, 0x86, 0x03, 0x18, 0x00, 0x00, 0x00,
+                       0x38, 0x00, 0x00, 0x00, 0xB5, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0E, 0x08,
+                       0x84, 0x02, 0x42, 0x0D, 0x04, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x0000001C
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000064
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000048
+      - offset:          0x00000020
+        scattered:       true
+        type:            GENERIC_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000068
+      - offset:          0x00000038
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000080
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000048
+      - offset:          0x0000003C
+        scattered:       true
+        type:            GENERIC_RELOC_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000039
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000084
+local-symbols:
+  - name:            EH_frame0
+    type:            N_SECT
+    sect:            3
+    value:           0x0000000000000048
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000039
+  - name:            __Z3barv.eh
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x000000000000007C
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z3foov.eh
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000060
+undefined-symbols:
+  - name:            __ZTIi
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_allocate_exception
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_throw
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[CIE:L[L0-9]+]]
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
+
diff --git a/test/mach-o/parse-eh-frame.yaml b/test/mach-o/parse-eh-frame.yaml
new file mode 100644 (file)
index 0000000..6453474
--- /dev/null
@@ -0,0 +1,88 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of __eh_frame (dwarf unwind) section.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x09, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
+                       0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000058
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+                       0x6B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000B
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[CIE:L[0-9]+]]
+# CHECK:     type:            unwind-cfi
+# CHECK:     content:         [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+# CHECK:                        01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 1C, 00, 00, 00, 88, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 44, 00, 00, 00, 6B, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:     references:
+# CHECK:       - kind:            negDelta32
+# CHECK:         offset:          4
+# CHECK:         target:          [[CIE]]
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
+# CHECK:   - name:            __Z3barv
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 09, 00, 00, 00, 5D, C3 ]
+# CHECK:   - name:            __Z3foov
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+
diff --git a/test/mach-o/parse-function.yaml b/test/mach-o/parse-function.yaml
new file mode 100644 (file)
index 0000000..bfd8e5c
--- /dev/null
@@ -0,0 +1,100 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t
+# RUN: lld -flavor darwin -arch x86_64 -r %t -print_atoms -o %t2 | FileCheck %s
+#
+# Test parsing of mach-o functions.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0xCC, 0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+global-symbols:
+  - name:            _myGlobal
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+  - name:            _myGlobalWeak
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000002
+  - name:            _myHidden
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    value:           0x0000000000000004
+  - name:            _myHiddenWeak
+    type:            N_SECT
+    scope:           [ N_EXT, N_PEXT ]
+    sect:            1
+    desc:            [ N_WEAK_DEF ]
+    value:           0x0000000000000007
+  - name:            _myStripNot
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_NO_DEAD_STRIP ]
+    value:           0x0000000000000010
+  - name:            _myResolver
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    desc:            [ N_SYMBOL_RESOLVER ]
+    value:           0x0000000000000011
+...
+
+# CHECK-NOT:  name:
+# CHECK:      content:         [ CC ]
+
+# CHECK:      name:   _myGlobal
+# CHECK:      scope:  global
+# CHECK:      content:         [ C3 ]
+
+# CHECK:      name:   _myGlobalWeak
+# CHECK:      scope:  global
+# CHECK:      content:         [ 90, C3 ]
+# CHECK:      merge:  as-weak
+
+# CHECK:      name:   _myHidden
+# CHECK:      scope:  hidden
+# CHECK:      content:         [ 90, 90, C3 ]
+
+# CHECK:      name:   _myHiddenWeak
+# CHECK:      scope:  hidden
+# CHECK:      content:         [ 90, 90, 90, C3 ]
+# CHECK:      merge:  as-weak
+
+# CHECK:      name:   _myStatic
+# CHECK-NOT:   scope:  global
+# CHECK-NOT:   scope:  hidden
+# CHECK:      content:         [ 90, 90, 90, 90, C3 ]
+
+# CHECK:      name:    _myStripNot
+# CHECK:      scope:   global
+# CHECK:      content:         [ CC ]
+# CHECK:      dead-strip:  never
+
+# CHECK:      name:    _myResolver
+# CHECK:      scope:   global
+# CHECK:      type:    resolver
+# CHECK:      content:         [ 31, C0, C3 ]
+
diff --git a/test/mach-o/parse-initializers32.yaml b/test/mach-o/parse-initializers32.yaml
new file mode 100644 (file)
index 0000000..ede7b90
--- /dev/null
@@ -0,0 +1,84 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x89, 0xE5,
+                       0x5D, 0xC3, 0x55, 0x89, 0xE5, 0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __mod_init_func
+    type:            S_MOD_INIT_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000044
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000004
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __DATA
+    section:         __mod_term_func
+    type:            S_MOD_TERM_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000104
+    content:         [ 0x0A, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _init
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _init2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000005
+  - name:            _term
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000A
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 05, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - type:            terminator-pointer
+# CHECK:    content:         [ 0A, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:  - name:            _init
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _init2
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _term
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
diff --git a/test/mach-o/parse-initializers64.yaml b/test/mach-o/parse-initializers64.yaml
new file mode 100644 (file)
index 0000000..c55a0ea
--- /dev/null
@@ -0,0 +1,105 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+                       0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5,
+                       0x5D, 0xC3 ]
+  - segment:         __DATA
+    section:         __mod_init_func
+    type:            S_MOD_INIT_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000008
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          1
+  - segment:         __DATA
+    section:         __mod_term_func
+    type:            S_MOD_TERM_FUNC_POINTERS
+    attributes:      [  ]
+    alignment:       8
+    address:         0x0000000000000108
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+global-symbols:
+  - name:            _init
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _init2
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000006
+  - name:            _term
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000C
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:     references:
+# CHECK:       - kind:        pointer64
+# CHECK:         offset:      0
+# CHECK:         target:      _init
+# CHECK:  - type:            initializer-pointer
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:     references:
+# CHECK:       - kind:        pointer64
+# CHECK:         offset:      0
+# CHECK:         target:      _init2
+# CHECK:  - type:            terminator-pointer
+# CHECK:    content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK:    dead-strip:      never
+# CHECK:     references:
+# CHECK:       - kind:        pointer64
+# CHECK:         offset:      0
+# CHECK:         target:      _term
+# CHECK:  - name:            _init
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 48, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _init2
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 48, 89, E5, 5D, C3 ]
+# CHECK:  - name:            _term
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 48, 89, E5, 5D, C3 ]
diff --git a/test/mach-o/parse-literals-error.yaml b/test/mach-o/parse-literals-error.yaml
new file mode 100644 (file)
index 0000000..8daeeca
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t 2> %t.err
+# RUN: FileCheck %s < %t.err
+#
+# Test for error if literal section is not correct size mulitple.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __literal8
+    type:            S_8BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       0
+    address:         0x0000000000000120
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D ]
+...
+
+# CHECK:       error:
+
diff --git a/test/mach-o/parse-literals.yaml b/test/mach-o/parse-literals.yaml
new file mode 100644 (file)
index 0000000..7f80ba5
--- /dev/null
@@ -0,0 +1,93 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000100
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+                       0x65, 0x72, 0x65, 0x00, 0x77, 0x6F, 0x72, 0x6C,
+                       0x00 ]
+  - segment:         __TEXT
+    section:         __literal4
+    type:            S_4BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000114
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x11, 0x12, 0x13, 0x14,
+                       0x28, 0x29, 0x2A, 0x2B ]
+  - segment:         __TEXT
+    section:         __literal8
+    type:            S_8BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000120
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F ]
+  - segment:         __TEXT
+    section:         __literal16
+    type:            S_16BYTE_LITERALS
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000130
+    content:         [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00 ]
+  - segment:         __TEXT
+    section:         __ustring
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       1
+    address:         0x0000000000000100
+    content:         [ 0x68, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00,
+                       0x6F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x68, 0x00,
+                       0x65, 0x00, 0x72, 0x00, 0x00, 0x00 ]
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 74, 68, 65, 72, 65, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            c-string
+# CHECK:    content:         [ 77, 6F, 72, 6C, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            utf16-string
+# CHECK:    content:         [ 68, 00, 65, 00, 6C, 00, 6C, 00, 6F, 00, 00, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            utf16-string
+# CHECK:    content:         [ 74, 00, 68, 00, 65, 00, 72, 00, 00, 00 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-4-byte
+# CHECK:    content:         [ 01, 02, 03, 04 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-4-byte
+# CHECK:    content:         [ 11, 12, 13, 14 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-4-byte
+# CHECK:    content:         [ 28, 29, 2A, 2B ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-8-byte
+# CHECK:    content:         [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-8-byte
+# CHECK:    content:         [ 28, 29, 2A, 2B, 2C, 2D, 2E, 2F ]
+# CHECK:  - scope:           hidden
+# CHECK:    type:            const-16-byte
+# CHECK:    content:         [ 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C,
+# CHECK:                       0D, 0E, 0F, 00 ]
+
diff --git a/test/mach-o/parse-non-lazy-pointers.yaml b/test/mach-o/parse-non-lazy-pointers.yaml
new file mode 100644 (file)
index 0000000..0b0ec5c
--- /dev/null
@@ -0,0 +1,98 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of non-lazy-pointer sections.
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00, 0x00,
+                       0x59, 0x8D, 0x81, 0x14, 0x00, 0x00, 0x00, 0x8D,
+                       0x81, 0x18, 0x00, 0x00, 0x00, 0x5D, 0xC3, 0x55,
+                       0x89, 0xE5, 0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x00000011
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000008
+      - offset:          0x0000000B
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000001C
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000008
+  - segment:         __IMPORT
+    section:         __pointers
+    type:            S_NON_LAZY_SYMBOL_POINTERS
+    attributes:      [  ]
+    address:         0x000000000000001C
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    indirect-syms:   [ 2, 2147483648 ]
+local-symbols:
+  - name:            _foo
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000017
+global-symbols:
+  - name:            _get
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK:defined-atoms:
+# CHECK:  - ref-name:        [[GOT1:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            got
+# CHECK:    content:         [ 00, 00, 00, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - ref-name:        [[GOT2:L[L0-9]+]]
+# CHECK:    scope:           hidden
+# CHECK:    type:            got
+# CHECK:    content:         [ 00, 00, 00, 00 ]
+# CHECK:    merge:           by-content
+# CHECK:  - name:            _get
+# CHECK:    scope:           global
+# CHECK:    content:         [ 55, 89, E5, E8, 00, 00, 00, 00, 59, 8D, 81, 14,
+# CHECK:                       00, 00, 00, 8D, 81, 18, 00, 00, 00, 5D, C3 ]
+# CHECK:     references:
+# CHECK:       - kind:            funcRel32
+# CHECK:         offset:          11
+# CHECK:         target:          [[GOT1]]
+# CHECK:       - kind:            funcRel32
+# CHECK:         offset:          17
+# CHECK:         target:          [[GOT2]]
+# CHECK:  - name:            _foo
+# CHECK:    content:         [ 55, 89, E5, 5D, C3 ]
+
+
diff --git a/test/mach-o/parse-relocs-x86.yaml b/test/mach-o/parse-relocs-x86.yaml
new file mode 100644 (file)
index 0000000..c7ce80b
--- /dev/null
@@ -0,0 +1,296 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t  | FileCheck %s \
+# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2  | FileCheck %s
+#
+# Test parsing and writing of x86 relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#  .text
+#_test:
+#      call _undef
+#      call _undef+2
+#      call _foo
+#      call _foo+2
+#   callw _undef
+#      callw _foo
+#      callw _foo+2
+#L1:
+#      movl    _undef, %eax
+#   movl       _x, %eax
+#   movl       _x+4, %eax
+#      movl    _x-L1(%eax), %eax
+#      movl    _x+4-L1(%eax), %eax
+#
+#_foo:
+#    ret
+#
+#  .data
+#_x:
+#  .long _undef
+#  .long _undef+7
+#  .long _foo
+#  .long _foo+3
+#  .long _test - .
+#  .long _test+3 - .
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xE8, 0xFB, 0xFF, 0xFF, 0xFF, 0xE8, 0xF8, 0xFF,
+                       0xFF, 0xFF, 0xE8, 0x2C, 0x00, 0x00, 0x00, 0xE8,
+                       0x29, 0x00, 0x00, 0x00, 0x66, 0xE8, 0xE8, 0xFF,
+                       0x66, 0xE8, 0x1F, 0x00, 0x66, 0xE8, 0x1D, 0x00,
+                       0xA1, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x3C, 0x00,
+                       0x00, 0x00, 0xA1, 0x40, 0x00, 0x00, 0x00, 0x8B,
+                       0x80, 0x1C, 0x00, 0x00, 0x00, 0x8B, 0x80, 0x20,
+                       0x00, 0x00, 0x00, 0xC3 ]
+    relocations:
+      - offset:          0x00000037
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000003C
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x00000031
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x0000003C
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000020
+      - offset:          0x0000002B
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        value:           0x0000003C
+      - offset:          0x00000026
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000021
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+      - offset:          0x0000001E
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          1
+        pc-rel:          true
+        value:           0x0000003B
+      - offset:          0x0000001A
+        type:            GENERIC_RELOC_VANILLA
+        length:          1
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000016
+        type:            GENERIC_RELOC_VANILLA
+        length:          1
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000010
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        value:           0x0000003B
+      - offset:          0x0000000B
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          1
+      - offset:          0x00000006
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+      - offset:          0x00000001
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          3
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000003C
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+                       0x3B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
+                       0xB4, 0xFF, 0xFF, 0xFF, 0xB3, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000014
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x00000050
+      - offset:          0x00000010
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000000
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000004C
+      - offset:          0x0000000C
+        scattered:       true
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        value:           0x0000003B
+      - offset:          0x00000008
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000004
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+      - offset:          0x00000000
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+local-symbols:
+  - name:            _test
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _foo
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000003B
+  - name:            _x
+    type:            N_SECT
+    sect:            2
+    value:           0x000000000000003C
+undefined-symbols:
+  - name:            _undef
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _x
+# CHECK:     type:            data
+# CHECK:     references:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          0
+# CHECK:         target:          _undef
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          4
+# CHECK:         target:          _undef
+# CHECK:         addend:          7
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          8
+# CHECK:         target:          _foo
+# CHECK-NOT:     addend:
+# CHECK:       - kind:            pointer32
+# CHECK:         offset:          12
+# CHECK:         target:          _foo
+# CHECK:         addend:          3
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          16
+# CHECK:         target:          _test
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          20
+# CHECK:         target:          _test
+# CHECK:         addend:          3
+# CHECK:  - name:            _test
+# CHECK:    references:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          1
+# CHECK:        target:          _undef
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          6
+# CHECK:        target:          _undef
+# CHECK:        addend:          2
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          11
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          16
+# CHECK:        target:          _foo
+# CHECK:        addend:          2
+# CHECK:      - kind:            branch16
+# CHECK:        offset:          22
+# CHECK:        target:          _undef
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch16
+# CHECK:        offset:          26
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            branch16
+# CHECK:        offset:          30
+# CHECK:        target:          _foo
+# CHECK:        addend:          2
+# CHECK:      - kind:            abs32
+# CHECK:        offset:          33
+# CHECK:        target:          _undef
+# CHECK:      - kind:            abs32
+# CHECK:        offset:          38
+# CHECK:        target:          _x
+# CHECK:      - kind:            abs32
+# CHECK:        offset:          43
+# CHECK:        target:          _x
+# CHECK:        addend:          4
+# CHECK:      - kind:            funcRel32
+# CHECK:        offset:          49
+# CHECK:        target:          _x
+# CHECK:        addend:          -32
+# CHECK:      - kind:            funcRel32
+# CHECK:        offset:          55
+# CHECK:        target:          _x
+# CHECK:        addend:          -28
+
diff --git a/test/mach-o/parse-section-no-symbol.yaml b/test/mach-o/parse-section-no-symbol.yaml
new file mode 100644 (file)
index 0000000..46d005a
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -print_atoms -o %t2 | FileCheck %s
+#
+# Test parsing of mach-o functions with no symbols at all.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC ]
+...
+
+# CHECK-NOT:  name:
+# CHECK:      content:         [ CC ]
diff --git a/test/mach-o/parse-tentative-defs.yaml b/test/mach-o/parse-tentative-defs.yaml
new file mode 100644 (file)
index 0000000..1757c8c
--- /dev/null
@@ -0,0 +1,88 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of tentative definitions, including size, scope, and alignment.
+#
+#
+# int tent4;
+# long tent8;
+# __attribute__((visibility("hidden"))) int tentHidden;
+# __attribute__((aligned(16))) int tent4_16;
+# __attribute__((aligned(32))) long tent64_32[8];
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __tex
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+undefined-symbols:
+  - name:            _tent4
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0200
+    value:           0x0000000000000004
+  - name:            _tent4_16
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0400
+    value:           0x0000000000000004
+  - name:            _tent64_32
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0500
+    value:           0x0000000000000040
+  - name:            _tent8
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    desc:            0x0300
+    value:           0x0000000000000008
+  - name:            _tentHidden
+    type:            N_UNDF
+    scope:           [ N_EXT, N_PEXT ]
+    desc:            0x0200
+    value:           0x0000000000000004
+...
+
+
+# CHECK:    defined-atoms:
+# CHECK:       name:             _tent4
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            4
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       4
+
+# CHECK:       name:             _tent4_16
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            4
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       16
+
+# CHECK:       name:             _tent64_32
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            64
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       32
+
+# CHECK:       name:             _tent8
+# CHECK:        scope:           global
+# CHECK:        type:            zero-fill
+# CHECK:        size:            8
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       8
+
+# CHECK:       name:             _tentHidden
+# CHECK:        scope:           hidden
+# CHECK:        type:            zero-fill
+# CHECK:        size:            4
+# CHECK:        merge:           as-tentative
+# CHECK:        alignment:       4
diff --git a/test/mach-o/parse-text-relocs-arm64.yaml b/test/mach-o/parse-text-relocs-arm64.yaml
new file mode 100644 (file)
index 0000000..38a52e7
--- /dev/null
@@ -0,0 +1,237 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN:  && lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of arm64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x94,
+                       0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0x39,
+                       0x20, 0x00, 0x40, 0x79, 0x20, 0x00, 0x40, 0xB9,
+                       0x20, 0x00, 0x40, 0xF9, 0x20, 0x00, 0xC0, 0x3D,
+                       0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xB9,
+                       0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xF9,
+                       0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x40, 0xF9 ]
+    relocations:
+      - offset:          0x00000034
+        type:            ARM64_RELOC_TLVP_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          5
+      - offset:          0x00000030
+        type:            ARM64_RELOC_TLVP_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x0000002C
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          6
+      - offset:          0x00000028
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          6
+      - offset:          0x00000024
+        type:            ARM64_RELOC_ADDEND
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16
+      - offset:          0x00000024
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000020
+        type:            ARM64_RELOC_ADDEND
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          16
+      - offset:          0x00000020
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000001C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000018
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000014
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000010
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          2
+      - offset:          0x00000008
+        type:            ARM64_RELOC_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x00000004
+        type:            ARM64_RELOC_ADDEND
+        length:          2
+        pc-rel:          false
+        extern:          false
+        symbol:          8
+      - offset:          0x00000004
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+      - offset:          0x00000000
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000038
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _func
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _v1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000038
+  - name:            ltmp1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000038
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _tlv
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _v2
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - name:            _v1
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:   - name:            _func
+# CHECK:     content:         [ 00, 00, 00, 94, 00, 00, 00, 94, 01, 00, 00, 90,
+# CHECK:                        20, 00, 40, 39, 20, 00, 40, 79, 20, 00, 40, B9,
+# CHECK:                        20, 00, 40, F9, 20, 00, C0, 3D, 01, 00, 00, 90,
+# CHECK:                        20, 00, 40, B9, 01, 00, 00, 90, 20, 00, 40, F9,
+# CHECK:                        00, 00, 00, 90, 00, 00, 40, F9 ]
+# CHECK:     references:
+# CHECK:       - kind:            branch26
+# CHECK:         offset:          0
+# CHECK:         target:          _foo
+# CHECK:       - kind:            branch26
+# CHECK:         offset:          4
+# CHECK:         target:          _foo
+# CHECK:         addend:          8
+# CHECK:       - kind:            page21
+# CHECK:         offset:          8
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12
+# CHECK:         offset:          12
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale2
+# CHECK:         offset:          16
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale4
+# CHECK:         offset:          20
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale8
+# CHECK:         offset:          24
+# CHECK:         target:          _v1
+# CHECK:       - kind:            offset12scale16
+# CHECK:         offset:          28
+# CHECK:         target:          _v1
+# CHECK:       - kind:            page21
+# CHECK:         offset:          32
+# CHECK:         target:          _v1
+# CHECK:         addend:          16
+# CHECK:       - kind:            offset12scale4
+# CHECK:         offset:          36
+# CHECK:         target:          _v1
+# CHECK:         addend:          16
+# CHECK:       - kind:            gotPage21
+# CHECK:         offset:          40
+# CHECK:         target:          _v2
+# CHECK:       - kind:            gotOffset12
+# CHECK:         offset:          44
+# CHECK:         target:          _v2
+# CHECK:       - kind:            tlvPage21
+# CHECK:         offset:          48
+# CHECK:         target:          _tlv
+# CHECK:       - kind:            tlvOffset12
+# CHECK:         offset:          52
+# CHECK:         target:          _tlv
+# CHECK: undefined-atoms:
+# CHECK:   - name:            _foo
+# CHECK:   - name:            _tlv
+# CHECK:   - name:            _v2
+
diff --git a/test/mach-o/parse-text-relocs-x86_64.yaml b/test/mach-o/parse-text-relocs-x86_64.yaml
new file mode 100644 (file)
index 0000000..6d0a52f
--- /dev/null
@@ -0,0 +1,204 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN:  && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of x86_64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references.  The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+#  call  _foo
+#  call  _foo+4
+#  movq  _foo@GOTPCREL(%rip), %rax
+#  pushq _foo@GOTPCREL(%rip)
+#  movl  _foo(%rip), %eax
+#  movl  _foo+4(%rip), %eax
+#  movb  $0x12, _foo(%rip)
+#  movw  $0x1234, _foo(%rip)
+#  movl  $0x12345678, _foo(%rip)
+#  movl  L2(%rip), %eax
+#  movb  $0x12, L2(%rip)
+#  movw  $0x1234, L2(%rip)
+#  movl  $0x12345678, L2(%rip)
+#
+#  .data
+#L2: .long 0
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x04, 0x00,
+                       0x00, 0x00, 0x48, 0x8B, 0x05, 0x04, 0x00, 0x00,
+                       0x00, 0xFF, 0x35, 0x04, 0x00, 0x00, 0x00, 0x8B,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x05, 0x04,
+                       0x00, 0x00, 0x00, 0xC6, 0x05, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0x12, 0x66, 0xC7, 0x05, 0xFE, 0xFF, 0xFF,
+                       0xFF, 0x34, 0x12, 0xC7, 0x05, 0xFC, 0xFF, 0xFF,
+                       0xFF, 0x78, 0x56, 0x34, 0x12, 0x8B, 0x05, 0x1A,
+                       0x00, 0x00, 0x00, 0xc6, 0x05, 0x13, 0x00, 0x00,
+                      0x00, 0x12, 0x66, 0xc7, 0x05, 0x0a, 0x00, 0x00,
+                      0x00, 0x34, 0x12, 0xc7, 0x05, 0x00, 0x00, 0x00,
+                      0x00, 0x78, 0x56, 0x34, 0x12 ]
+    relocations:
+      - offset:          0x00000055
+        type:            X86_64_RELOC_SIGNED_4
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x0000004d
+        type:            X86_64_RELOC_SIGNED_2
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x00000045
+        type:            X86_64_RELOC_SIGNED_1
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x0000003F
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          false
+        symbol:          2
+      - offset:          0x00000035
+        type:            X86_64_RELOC_SIGNED_4
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000002D
+        type:            X86_64_RELOC_SIGNED_2
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000025
+        type:            X86_64_RELOC_SIGNED_1
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000001F
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000019
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000013
+        type:            X86_64_RELOC_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000D
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000006
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000001
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000005D
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            _test
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - ref-name:        [[LABEL:L[0-9]+]]
+# CHECK:     type:            data
+# CHECK:     content:         [ 00, 00, 00, 00 ]
+# CHECK:  - name:            _test
+# CHECK:    references:
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          1
+# CHECK:        target:          _foo
+# CHECK:      - kind:            branch32
+# CHECK:        offset:          6
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32GotLoad
+# CHECK:        offset:          13
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32Got
+# CHECK:        offset:          19
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32
+# CHECK:        offset:          25
+# CHECK:        target:          _foo
+# CHECK:      - kind:            ripRel32
+# CHECK:        offset:          31
+# CHECK:        target:          _foo
+# CHECK:        addend:          4
+# CHECK:      - kind:            ripRel32Minus1
+# CHECK:        offset:          37
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus2
+# CHECK:        offset:          45
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus4
+# CHECK:        offset:          53
+# CHECK:        target:          _foo
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Anon
+# CHECK:        offset:          63
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus1Anon
+# CHECK:        offset:          69
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus2Anon
+# CHECK:        offset:          77
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
+# CHECK:      - kind:            ripRel32Minus4Anon
+# CHECK:        offset:          85
+# CHECK:        target:          [[LABEL]]
+# CHECK-NOT:    addend:
diff --git a/test/mach-o/parse-tlv-relocs-x86-64.yaml b/test/mach-o/parse-tlv-relocs-x86-64.yaml
new file mode 100644 (file)
index 0000000..78b1784
--- /dev/null
@@ -0,0 +1,100 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN:  && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing of x86_64 tlv relocations.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x3D, 0x00,
+                       0x00, 0x00, 0x00, 0xFF, 0x17, 0x8B, 0x00, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000007
+        type:            X86_64_RELOC_TLV
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __thread_data
+    type:            S_THREAD_LOCAL_REGULAR
+    attributes:      [  ]
+    alignment:       4
+    address:         0x0000000000000014
+    content:         [ 0x07, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __thread_vars
+    type:            S_THREAD_LOCAL_VARIABLES
+    attributes:      [  ]
+    address:         0x0000000000000018
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+local-symbols:
+  - name:            '_x$tlv$init'
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _x
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000018
+undefined-symbols:
+  - name:            __tlv_bootstrap
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+page-size:       0x00000000
+...
+
+# CHECK:        - name:            _x
+# CHECK-NEXT:     scope:           global
+# CHECK-NEXT:     type:            tlv-thunk
+# CHECK-NOT:    - name:
+# CHECK:          references:
+# CHECK-NEXT:       - kind:            pointer64
+# CHECK-NEXT:         offset:          0
+# CHECK-NEXT:         target:          __tlv_bootstrap
+# CHECK-NEXT:       - kind:            tlvInitSectionOffset
+# CHECK-NEXT:         offset:          16
+# CHECK-NEXT:         target:          '_x$tlv$init'
+# CHECK:        - name:            _main
+# CHECK-NOT:    - name:
+# CHECK-NEXT:     scope:           global
+# CHECK:          references:
+# CHECK-NEXT:      - kind:            ripRel32Tlv
+# CHECK-NEXT:        offset:          7
+# CHECK-NEXT:        target:          _x
diff --git a/test/mach-o/re-exported-dylib-ordinal.yaml b/test/mach-o/re-exported-dylib-ordinal.yaml
new file mode 100644 (file)
index 0000000..ff4d756
--- /dev/null
@@ -0,0 +1,46 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: %p/Inputs/re-exported-dylib-ordinal.yaml \
+# RUN: %p/Inputs/re-exported-dylib-ordinal2.yaml \
+# RUN: %p/Inputs/re-exported-dylib-ordinal3.yaml -dylib -o %t \
+# RUN:  && llvm-nm -m %t | FileCheck %s
+#
+# Test that when one dylib A re-exports dylib B that using a symbol from B
+# gets recorded as coming from A.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _test
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       (undefined) external _bar (from libfoo)
+# CHECK:       (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/rpath.yaml b/test/mach-o/rpath.yaml
new file mode 100644 (file)
index 0000000..6391493
--- /dev/null
@@ -0,0 +1,38 @@
+# Check we handle -rpath correctly:
+# RUN: lld -flavor darwin -arch x86_64 -rpath @loader_path/../Frameworks \
+# RUN:     %p/Inputs/x86_64/libSystem.yaml %s -o %t
+# RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       4
+    address:         0x0000000000000000
+    content:         [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+                       0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+                       0x31, 0xC0, 0xC3 ]
+local-symbols:
+  - name:            _myStatic
+    type:            N_SECT
+    sect:            1
+    value:           0x000000000000000B
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+...
+
+
+# CHECK-BINARY-WRITE: cmd LC_RPATH
+# CHECK-BINARY-WRITE-NEXT:  cmdsize 40
+# CHECK-BINARY-WRITE-NEXT:  path @loader_path/../Frameworks (offset 12)
diff --git a/test/mach-o/run-tlv-pass-x86-64.yaml b/test/mach-o/run-tlv-pass-x86-64.yaml
new file mode 100644 (file)
index 0000000..dd524c0
--- /dev/null
@@ -0,0 +1,144 @@
+# RUN: lld -flavor darwin -macosx_version_min 10.7 -arch x86_64 -print_atoms %s -o %t | FileCheck %s
+# RUN: not lld -flavor darwin -macosx_version_min 10.6 -arch x86_64 -o %t %s 2> %t2
+# RUN: FileCheck < %t2 %s --check-prefix=CHECK-ERROR
+# RUN: llvm-objdump -macho -private-headers %t | FileCheck %s --check-prefix=CHECK-LOADCMDS
+#
+# Test parsing of x86_64 tlv relocations.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       16
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x3D, 0x00,
+                       0x00, 0x00, 0x00, 0xFF, 0x17, 0x8B, 0x00, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000007
+        type:            X86_64_RELOC_TLV
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __thread_bss
+    type:            S_THREAD_LOCAL_ZEROFILL
+    attributes:      [  ]
+    alignment:       4
+    address:         0x0000000000000014
+    size:            4
+  - segment:         __DATA
+    section:         __thread_vars
+    type:            S_THREAD_LOCAL_VARIABLES
+    attributes:      [  ]
+    address:         0x0000000000000018
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000010
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          0
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          3
+  - segment:         __DATA
+    section:         __dummy
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x00000000000000C0
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            '_x$tlv$init'
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000014
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _x
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000018
+  - name:            '__tlv_bootstrap'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x00000000000000C0
+  - name:            'dyld_stub_binder'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x00000000000000C8
+  - name:            'start'
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x00000000000000D0
+page-size:       0x00000000
+...
+
+# CHECK:       - name:            _x
+# CHECK-NEXT:    scope:           global
+# CHECK-NEXT:    type:            tlv-thunk
+# CHECK-NOT:   - name:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            pointer64
+# CHECK-NEXT:         offset:          0
+# CHECK-NEXT:         target:          __tlv_bootstrap
+# CHECK-NEXT:       - kind:            tlvInitSectionOffset
+# CHECK-NEXT:         offset:          16
+# CHECK-NEXT:         target:          '_x$tlv$init'
+# CHECK:       - name:            '_x$tlv$init'
+# CHECK-NEXT:    type:            tlv-zero-fill
+# CHECK:        - name:            _main
+# CHECK-NOT:    - name:
+# CHECK:          references:
+# CHECK-NEXT:       - kind:            ripRel32
+# CHECK-NEXT:         offset:          7
+# CHECK-NEXT:         target:          L[[ID:[0-9]+]]
+# CHECK:        - ref-name:        L[[ID]]
+# CHECK-NEXT:     scope:           hidden
+# CHECK-NEXT:     type:            tlv-initializer-ptr
+# CHECK-NEXT:     content:         [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK-NEXT:     alignment:       8
+# CHECK-NEXT:     permissions:     rw-
+# CHECK-NEXT:     references:
+# CHECK-NEXT:       - kind:            pointer64
+# CHECK-NEXT:         offset:          0
+# CHECK-NEXT:         target:          _x
+
+# CHECK-ERROR: targeted OS version does not support use of thread local variables in _main for architecture x86_64
+
+# CHECK-LOADCMDS: sectname __thread_bss
+# CHECK-LOADCMDS:   segname __DATA
+# CHECK-LOADCMDS:      addr 0x{{[0-9A-F]*}}
+# CHECK-LOADCMDS:      size 0x0000000000000004
+# CHECK-LOADCMDS:    offset 0
+# CHECK-LOADCMDS:     align 2^2 (4)
+# CHECK-LOADCMDS:    reloff 0
+# CHECK-LOADCMDS:    nreloc 0
+# CHECK-LOADCMDS:      type S_THREAD_LOCAL_ZEROFILL
diff --git a/test/mach-o/sdk-version-error.yaml b/test/mach-o/sdk-version-error.yaml
new file mode 100644 (file)
index 0000000..2607bb8
--- /dev/null
@@ -0,0 +1,22 @@
+# RUN: not lld -flavor darwin -arch x86_64 -sdk_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# ERROR: malformed sdkVersion value
\ No newline at end of file
diff --git a/test/mach-o/sectalign.yaml b/test/mach-o/sectalign.yaml
new file mode 100644 (file)
index 0000000..f0df9f9
--- /dev/null
@@ -0,0 +1,80 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN:    -sectalign __DATA __custom 0x800 -sectalign __TEXT __text 0x400 \
+# RUN:    %p/Inputs/x86_64/libSystem.yaml -o %t \
+# RUN: && llvm-readobj -sections %t | FileCheck %s
+#
+# Test -sectalign option on __text and a custom section.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,
+                       0x5D, 0xC3 ]
+    relocations:
+      - offset:          0x0000000C
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000006
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000014
+    content:         [ 0x0A, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __custom
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000018
+    content:         [ 0x0A, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _a
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            2
+    value:           0x0000000000000014
+  - name:            _b
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            3
+    value:           0x0000000000000018
+  - name:            _get
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:  Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Address: 0xC00
+
+# CHECK:  Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Address: 0x1000
+
+# CHECK:  Name: __custom (5F 5F 63 75 73 74 6F 6D 00 00 00 00 00 00 00 00)
+# CHECK:  Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK:  Address: 0x1800
+
diff --git a/test/mach-o/sectattrs.yaml b/test/mach-o/sectattrs.yaml
new file mode 100644 (file)
index 0000000..21113dc
--- /dev/null
@@ -0,0 +1,30 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN:    %p/Inputs/x86_64/libSystem.yaml -o %t \
+# RUN: && llvm-objdump -private-headers %t | FileCheck %s
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x8B, 0x05, 0x00, 0x00,
+                       0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,
+                       0x5D, 0xC3 ]
+global-symbols:
+  - name:            _get
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:  PURE_INSTRUCTIONS SOME_INSTRUCTIONS
+
diff --git a/test/mach-o/sectcreate.yaml b/test/mach-o/sectcreate.yaml
new file mode 100644 (file)
index 0000000..51c59dc
--- /dev/null
@@ -0,0 +1,12 @@
+# RUN: lld -flavor darwin -r -arch x86_64 -o %t -sectcreate __DATA __data \
+# RUN:   %p/Inputs/hw.raw_bytes -print_atoms | FileCheck %s
+
+# CHECK: --- !native
+# CHECK: path:            '<linker-internal>'
+# CHECK: defined-atoms:
+# CHECK:   - scope:           global
+# CHECK:     type:            sectcreate
+# CHECK:     content:         [ 68, 65, 6C, 6C, 6F, 0A ]
+# CHECK:     section-choice:  custom-required
+# CHECK:     section-name:    __DATA/__data
+# CHECK:     dead-strip:      never
diff --git a/test/mach-o/seg-protection-arm64.yaml b/test/mach-o/seg-protection-arm64.yaml
new file mode 100644 (file)
index 0000000..f63b33a
--- /dev/null
@@ -0,0 +1,78 @@
+# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            start
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+
+...
+
+# CHECK: Load command 0
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __PAGEZERO
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot ---
+# CHECK:   initprot ---
+# CHECK:    nsects 0
+# CHECK:     flags (none)
+# CHECK: Load command 1
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 152
+# CHECK:   segname __TEXT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot r-x
+# CHECK:   initprot r-x
+# CHECK:    nsects 1
+# CHECK:     flags (none)
+# CHECK: Section
+# CHECK:   sectname __text
+# CHECK:    segname __TEXT
+# CHECK:       addr
+# CHECK:       size
+# CHECK:     offset
+# CHECK:      align 2^0 (1)
+# CHECK:     reloff 0
+# CHECK:     nreloc 0
+# CHECK:       type S_REGULAR
+# CHECK: attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
+# CHECK:  reserved1 0
+# CHECK:  reserved2 0
+# CHECK: Load command 2
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __LINKEDIT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot r--
+# CHECK:   initprot r--
+# CHECK:    nsects 0
+# CHECK:     flags (none)
diff --git a/test/mach-o/seg-protection-x86_64.yaml b/test/mach-o/seg-protection-x86_64.yaml
new file mode 100644 (file)
index 0000000..474f72f
--- /dev/null
@@ -0,0 +1,78 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            start
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
+
+...
+
+# CHECK: Load command 0
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __PAGEZERO
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot ---
+# CHECK:   initprot ---
+# CHECK:    nsects 0
+# CHECK:     flags (none)
+# CHECK: Load command 1
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 152
+# CHECK:   segname __TEXT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot rwx
+# CHECK:   initprot r-x
+# CHECK:    nsects 1
+# CHECK:     flags (none)
+# CHECK: Section
+# CHECK:   sectname __text
+# CHECK:    segname __TEXT
+# CHECK:       addr
+# CHECK:       size
+# CHECK:     offset
+# CHECK:      align 2^0 (1)
+# CHECK:     reloff 0
+# CHECK:     nreloc 0
+# CHECK:       type S_REGULAR
+# CHECK: attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
+# CHECK:  reserved1 0
+# CHECK:  reserved2 0
+# CHECK: Load command 2
+# CHECK:       cmd LC_SEGMENT_64
+# CHECK:   cmdsize 72
+# CHECK:   segname __LINKEDIT
+# CHECK:    vmaddr
+# CHECK:    vmsize
+# CHECK:   fileoff
+# CHECK:  filesize
+# CHECK:   maxprot rwx
+# CHECK:   initprot r--
+# CHECK:    nsects 0
+# CHECK:     flags (none)
diff --git a/test/mach-o/source-version.yaml b/test/mach-o/source-version.yaml
new file mode 100644 (file)
index 0000000..4e0eaee
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: not lld -flavor darwin -arch x86_64 -source_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR
+# RUN: lld -flavor darwin -arch x86_64 -source_version 10.1.2.3.4 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# ERROR: malformed source_version value
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:       cmd LC_SOURCE_VERSION
+# CHECK:   cmdsize 16
+# CHECK:   version 10.1.2.3.4
\ No newline at end of file
diff --git a/test/mach-o/stack-size.yaml b/test/mach-o/stack-size.yaml
new file mode 100644 (file)
index 0000000..048282c
--- /dev/null
@@ -0,0 +1,24 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DEFAULT %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -stack_size 31415926000 %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-EXPLICIT %s
+# RUN: not lld -flavor darwin -arch x86_64 -stack_size 0x31415926530 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED
+# RUN: not lld -flavor darwin -arch x86_64 -stack_size hithere %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX
+
+--- !native
+defined-atoms:
+   - name:            _main
+     scope:           global
+     content:         []
+
+# CHECK-DEFAULT:       cmd LC_MAIN
+# CHECK-DEFAULT: stacksize 0
+
+# CHECK-EXPLICIT:       cmd LC_MAIN
+# CHECK-EXPLICIT: stacksize 3384796143616
+
+# CHECK-ERROR-MISPAGED: error: stack_size must be a multiple of page size (0x1000)
+
+# CHECK-ERROR-NOTHEX: error: stack_size expects a hex number
diff --git a/test/mach-o/string-table.yaml b/test/mach-o/string-table.yaml
new file mode 100644 (file)
index 0000000..eec2c77
--- /dev/null
@@ -0,0 +1,66 @@
+# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t
+# RUN: obj2yaml %t | FileCheck %s
+#
+# Test that the string table contains a ' ' as its first symbol
+#
+
+--- !mach-o
+arch:            x86
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0x58, 0x8D, 0x80, 0x16, 0x00,
+                       0x00, 0x00, 0x89, 0x04, 0x24, 0xE8, 0xE6, 0xFF,
+                       0xFF, 0xFF, 0x31, 0xC0, 0x83, 0xC4, 0x08, 0x5D,
+                       0xC3 ]
+    relocations:
+      - offset:          0x00000016
+        type:            GENERIC_RELOC_VANILLA
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x0000000E
+        scattered:       true
+        type:            GENERIC_RELOC_LOCAL_SECTDIFF
+        length:          2
+        pc-rel:          false
+        value:           0x00000021
+      - offset:          0x00000000
+        scattered:       true
+        type:            GENERIC_RELOC_PAIR
+        length:          2
+        pc-rel:          false
+        value:           0x0000000B
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000021
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _printf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:  StringTable:
+# CHECK-NEXT:  - ' '
+# CHECK-NEXT:  - __mh_execute_header
+# CHECK-NEXT:  - _main
+# CHECK-NEXT:  - _printf
+# CHECK-NEXT:  - dyld_stub_binder
+# CHECK-NEXT:  - ''
diff --git a/test/mach-o/subsections-via-symbols-default.yaml b/test/mach-o/subsections-via-symbols-default.yaml
new file mode 100644 (file)
index 0000000..93ddbc9
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t
+# RUN: llvm-readobj -file-headers %t | FileCheck %s
+
+# Make sure that we have an objc image info in the output.  It should have
+# been generated by the objc pass.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+compat-version:  0.0
+current-version: 0.0
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __DATA
+    section:         __objc_imageinfo
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_NO_DEAD_STRIP ]
+    address:         0x0000000000000100
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00 ]
+...
+
+# The ObjC pass creates a new image info in a new MachoFile internal to the pass.
+# Make sure that we still have MH_SUBSECTIONS_VIA_SYMBOLS in the output file, even
+# though that file in the ObjCPass didn't get it set from being parsed.
+
+# CHECK: MH_SUBSECTIONS_VIA_SYMBOLS
\ No newline at end of file
diff --git a/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml b/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml
new file mode 100644 (file)
index 0000000..b402ae3
--- /dev/null
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined dynamic_lookup %s -o %t %p/Inputs/x86_64/libSystem.yaml
+#
+# Sanity check '-twolevel_namespace -undefined dynamic_lookup'.
+# This should pass without error, even though '_bar' is undefined.
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
diff --git a/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml b/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml
new file mode 100644 (file)
index 0000000..1ac704c
--- /dev/null
@@ -0,0 +1,23 @@
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined warning %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \
+# RUN:   FileCheck --check-prefix=CHECK-WARNING %s
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \
+# RUN:   FileCheck --check-prefix=CHECK-SUPPRESS %s
+
+--- !native
+defined-atoms:
+  - name:            _main
+    scope:           global
+    content:         [ E9, 00, 00, 00, 00 ]
+    alignment:       16
+    references:
+      - kind:            branch32
+        offset:          1
+        target:          _bar
+undefined-atoms:
+  - name:            _bar
+
+# Make sure that the driver issues an error diagnostic about this combination
+# being invalid.
+#
+# CHECK-WARNING:  can't use -undefined warning or suppress with -twolevel_namespace
+# CHECK-SUPPRESS: can't use -undefined warning or suppress with -twolevel_namespace
\ No newline at end of file
diff --git a/test/mach-o/unwind-info-simple-arm64.yaml b/test/mach-o/unwind-info-simple-arm64.yaml
new file mode 100644 (file)
index 0000000..4caaf35
--- /dev/null
@@ -0,0 +1,267 @@
+# RUN: lld -flavor darwin -arch arm64 -o %t %s \
+# RUN: %p/Inputs/unwind-info-simple-arm64.yaml -e _main %p/Inputs/arm64/libSystem.yaml
+# RUN: llvm-objdump -unwind-info %t | FileCheck %s
+
+--- !mach-o
+arch:            arm64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    alignment:       2
+    address:         0x0000000000000000
+    content:         [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
+                       0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
+                       0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
+                       0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
+                       0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
+                       0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
+                       0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
+                       0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
+                       0x3F, 0x04, 0x00, 0x71, 0x81, 0x00, 0x00, 0x54,
+                       0x00, 0x00, 0x00, 0x94, 0xFD, 0x7B, 0xC1, 0xA8,
+                       0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x94,
+                       0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+                       0x00, 0x00, 0x00, 0x94 ]
+    relocations:
+      - offset:          0x00000070
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000064
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          7
+      - offset:          0x00000060
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          12
+      - offset:          0x00000058
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          11
+      - offset:          0x0000004C
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          13
+      - offset:          0x00000048
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          8
+      - offset:          0x00000044
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          8
+      - offset:          0x00000034
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          10
+      - offset:          0x00000024
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          13
+      - offset:          0x00000020
+        type:            ARM64_RELOC_GOT_LOAD_PAGEOFF12
+        length:          2
+        pc-rel:          false
+        extern:          true
+        symbol:          8
+      - offset:          0x0000001C
+        type:            ARM64_RELOC_GOT_LOAD_PAGE21
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          8
+      - offset:          0x0000000C
+        type:            ARM64_RELOC_BRANCH26
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          10
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       2
+    address:         0x0000000000000074
+    content:         [ 0xFF, 0x9B, 0xAF, 0x80, 0x00, 0x03, 0x27, 0x00,
+                       0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+                       0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+                       0x01, 0x28, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0xD0, 0xFF, 0xFF, 0xFF ]
+    relocations:
+      - offset:          0x00000030
+        type:            ARM64_RELOC_POINTER_TO_GOT
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          9
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       8
+    address:         0x00000000000000A8
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000040
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000038
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          2
+      - offset:          0x00000030
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          true
+        symbol:          14
+      - offset:          0x00000020
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+      - offset:          0x00000000
+        type:            ARM64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+local-symbols:
+  - name:            ltmp0
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+  - name:            ltmp14
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000074
+  - name:            GCC_except_table1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000074
+  - name:            ltmp21
+    type:            N_SECT
+    sect:            3
+    value:           0x00000000000000A8
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000028
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000068
+undefined-symbols:
+  - name:            __Unwind_Resume
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __ZTIi
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            __ZTIl
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_allocate_exception
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_begin_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_end_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_throw
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___gxx_personality_v0
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK: Contents of __unwind_info section:
+# CHECK:   Version:                                   0x1
+# CHECK:   Common encodings array section offset:     0x1c
+# CHECK:   Number of common encodings in array:       0x0
+# CHECK:   Personality function array section offset: 0x1c
+# CHECK:   Number of personality functions in array:  0x1
+# CHECK:   Index array section offset:                0x20
+# CHECK:   Number of indices in array:                0x2
+# CHECK:   Common encodings: (count = 0)
+# CHECK:   Personality functions: (count = 1)
+# CHECK:     personality[1]: 0x00004020
+# CHECK:   Top level indices: (count = 2)
+# CHECK:     [0]: function offset=0x00003e68, 2nd level page offset=0x00000040, LSDA offset=0x00000038
+# CHECK:     [1]: function offset=0x00003edc, 2nd level page offset=0x00000000, LSDA offset=0x00000040
+# CHECK:   LSDA descriptors:
+# CHECK:     [0]: function offset=0x00003e90, LSDA offset=0x00003f6c
+# CHECK:   Second level indices:
+# CHECK:     Second level index[0]: offset in section=0x00000040, base function offset=0x00003e68
+# CHECK:       [0]: function offset=0x00003e68, encoding=0x04000000
+# CHECK:       [1]: function offset=0x00003e90, encoding=0x54000000
+# CHECK:       [2]: function offset=0x00003ed0, encoding=0x04000000
+# CHECK-NOT: Contents of __compact_unwind section
+
+
+
diff --git a/test/mach-o/unwind-info-simple-x86_64.yaml b/test/mach-o/unwind-info-simple-x86_64.yaml
new file mode 100644 (file)
index 0000000..797c5a3
--- /dev/null
@@ -0,0 +1,133 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e _main %p/Inputs/x86_64/libSystem.yaml
+# RUN: llvm-objdump -unwind-info %t | FileCheck %s
+
+# CHECK: Contents of __unwind_info section:
+# CHECK:   Version:                                   0x1
+# CHECK:   Common encodings array section offset:     0x1c
+# CHECK:   Number of common encodings in array:       0x0
+# CHECK:   Personality function array section offset: 0x1c
+# CHECK:   Number of personality functions in array:  0x1
+# CHECK:   Index array section offset:                0x20
+# CHECK:   Number of indices in array:                0x2
+# CHECK:   Common encodings: (count = 0)
+# CHECK:   Personality functions: (count = 1)
+# CHECK:     personality[1]: 0x00001000
+# CHECK:   Top level indices: (count = 2)
+# CHECK:     [0]: function offset=0x00000efb, 2nd level page offset=0x00000040, LSDA offset=0x00000038
+# CHECK:     [1]: function offset=0x00000f00, 2nd level page offset=0x00000000, LSDA offset=0x00000040
+# CHECK:   LSDA descriptors:
+# CHECK:     [0]: function offset=0x00000efb, LSDA offset=0x00000f00
+# CHECK:   Second level indices:
+# CHECK:     Second level index[0]: offset in section=0x00000040, base function offset=0x00000efb
+# CHECK:       [0]: function offset=0x00000efb, encoding=0x51000000
+# CHECK:       [1]: function offset=0x00000efc, encoding=0x01000000
+# CHECK:       [2]: function offset=0x00000efd, encoding=0x04000018
+# CHECK:       [3]: function offset=0x00000efe, encoding=0x04000040
+# CHECK:       [4]: function offset=0x00000eff, encoding=0x00000000
+# CHECK-NOT: Contents of __compact_unwind section
+
+--- !native
+path:            '<linker-internal>'
+defined-atoms:
+  - name:            GCC_except_table1
+    type:            unwind-lsda
+    content:         [ FF, 9B, A2, 80, 80, 00, 03, 1A, 08, 00, 00, 00,
+                       05, 00, 00, 00, 1A, 00, 00, 00, 01, 0D, 00, 00,
+                       00, 64, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00,
+                       04, 00, 00, 00 ]
+  - type:            compact-unwind
+    content:         [ 40, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+                       00, 00, 00, 41, 00, 00, 00, 00, 00, 00, 00, 00,
+                       E0, 00, 00, 00, 00, 00, 00, 00 ]
+    references:
+      - kind:            pointer64Anon
+        offset:          0
+        target:          __Z3barv
+      - kind:            pointer64
+        offset:          16
+        target:          ___gxx_personality_v0
+      - kind:            pointer64Anon
+        offset:          24
+        target:          GCC_except_table1
+  - type:            compact-unwind
+    content:         [ C0, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+                       00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+                       00, 00, 00, 00, 00, 00, 00, 00 ]
+    references:
+      - kind:            pointer64Anon
+        offset:          0
+        target:          _main
+  - type:            compact-unwind
+    content:         [ C1, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+                       00, 00, 00, 04, 00, 00, 00, 00, 00, 00, 00, 00,
+                       00, 00, 00, 00, 00, 00, 00, 00 ]
+    references:
+      - kind:            pointer64Anon
+        offset:          0
+        target:          _needsDwarfButNoCompactUnwind
+
+# Generic x86_64 CIE:
+  - name:            LCIE
+    type:            unwind-cfi
+    content:         [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+                       01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 1C, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _needsDwarfButNoCompactUnwind
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 44, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _needsDwarfSaysCompactUnwind
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 6C, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _main
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+  - name:            __Z3barv
+    scope:           global
+    content:         [ C3 ]
+  - name:            _main
+    scope:           global
+    content:         [ C3 ]
+  - name:            _needsDwarfButNoCompactUnwind
+    scope:           global
+    content:         [ C3 ]
+  - name:            _needsDwarfSaysCompactUnwind
+    scope:           global
+    content:         [ C3 ]
+  - name:            _noUnwindData
+    scope:           global
+    content:         [ C3 ]
+
+shared-library-atoms:
+  - name:            ___gxx_personality_v0
+    load-name:       '/usr/lib/libc++abi.dylib'
+    type:            unknown
diff --git a/test/mach-o/upward-dylib-load-command.yaml b/test/mach-o/upward-dylib-load-command.yaml
new file mode 100644 (file)
index 0000000..54e31f6
--- /dev/null
@@ -0,0 +1,48 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN:     -install_name /usr/lib/libbar.dylib %p/Inputs/x86_64/libSystem.yaml -o %t1.dylib
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -upward_library  %t1.dylib \
+# RUN:      -install_name /usr/lib/libfoo.dylib %p/Inputs/x86_64/libSystem.yaml -o %t
+# RUN: llvm-objdump -private-headers %t | FileCheck %s
+#
+#
+# Test upward linking: 1) build libbar.dylib, 2) build libfoo.dylib and upward
+# like with libbar.dylib, 3) dump load commands of libfoo and verify upward link.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+                       0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000008
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _bar
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+...
+
+
+# CHECK:                     cmd LC_LOAD_UPWARD_DYLIB
+# CHECK-NEXT:        cmdsize 48
+# CHECK-NEXT:           name /usr/lib/libbar.dylib (offset 24)
diff --git a/test/mach-o/upward-dylib-paths.yaml b/test/mach-o/upward-dylib-paths.yaml
new file mode 100644 (file)
index 0000000..53ff9fa
--- /dev/null
@@ -0,0 +1,18 @@
+#
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN:        -path_exists /Custom/Frameworks \
+# RUN:        -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN:        -path_exists /usr/lib \
+# RUN:        -path_exists /usr/lib/libfoo.dylib \
+# RUN:        -path_exists /opt/stuff/libstuff.dylib \
+# RUN:        -F/Custom/Frameworks \
+# RUN:        -upward_framework Bar \
+# RUN:        -upward-lfoo \
+# RUN:        -upward_library /opt/stuff/libstuff.dylib \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Found upward framework /Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found upward library /usr/lib/libfoo.dylib
+
+
diff --git a/test/mach-o/usage.yaml b/test/mach-o/usage.yaml
new file mode 100644 (file)
index 0000000..20a5062
--- /dev/null
@@ -0,0 +1,8 @@
+# RUN: not lld -flavor darwin | FileCheck %s
+#
+# Test that running darwin linker with no option prints out usage message.
+#
+
+
+# CHECK:                 USAGE:
+# CHECK:                 -arch
diff --git a/test/mach-o/use-dylib.yaml b/test/mach-o/use-dylib.yaml
new file mode 100644 (file)
index 0000000..c173cc0
--- /dev/null
@@ -0,0 +1,39 @@
+# RUN: lld -flavor darwin -arch x86_64 %s \
+# RUN: %p/Inputs/use-simple-dylib.yaml %p/Inputs/x86_64/libSystem.yaml -dylib -o %t.dylib
+# RUN: llvm-objdump -private-headers %t.dylib | FileCheck %s
+
+# This test ensures that we have a LC_LOAD_DYLIB for libspecial.dylib even though we don't
+# use any atoms from it.  This matches the ld64 behaviour.
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00,
+                       0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00,
+                       0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+# CHECK:           cmd LC_LOAD_DYLIB
+# CHECK:          name libspecial.dylib (offset 24)
+# CHECK:       current version 1.0.0
+# CHECK: compatibility version 1.0.0
+# CHECK:           cmd LC_LOAD_DYLIB
+# CHECK:          name /usr/lib/libSystem.B.dylib (offset 24)
+# CHECK:       current version 1.0.0
+# CHECK: compatibility version 1.0.0
diff --git a/test/mach-o/use-simple-dylib.yaml b/test/mach-o/use-simple-dylib.yaml
new file mode 100644 (file)
index 0000000..658be16
--- /dev/null
@@ -0,0 +1,73 @@
+# RUN: lld -flavor darwin -arch x86_64 -print_atoms -r %s \
+# RUN: %p/Inputs/use-simple-dylib.yaml -o %t | FileCheck %s
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+                       0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00,
+                       0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00,
+                       0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00,
+                       0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _myGlobal
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myGlobalWeak
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myHidden
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myHiddenWeak
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myResolver
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myStatic
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _myVariablePreviouslyKnownAsPrivateExtern
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+
+# CHECK: undefined-atoms:
+# CHECK:   - name:            _myStatic
+# CHECK:   - name:            _myVariablePreviouslyKnownAsPrivateExtern
+# CHECK: shared-library-atoms:
+# CHECK:   - name:            _myGlobal
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myGlobalWeak
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myHidden
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myHiddenWeak
+# CHECK:     load-name:       libspecial.dylib
+# CHECK:   - name:            _myResolver
+# CHECK:     load-name:       libspecial.dylib
diff --git a/test/mach-o/version-min-load-command-object.yaml b/test/mach-o/version-min-load-command-object.yaml
new file mode 100644 (file)
index 0000000..33001cc
--- /dev/null
@@ -0,0 +1,35 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r -macosx_version_min 10.8 && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r %p/Inputs/no-version-min-load-command-object.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+
+# If we are emitting an object file, then we only emit a min version load command if the source object file(s) all have
+# version(s) and either known platforms or contain min version load commands themselves.
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+min-os-version-kind: LC_VERSION_MIN_MACOSX
+min-os-version: 10.8
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_VERSION_MIN_MACOSX
+# CHECK:   cmdsize 16
+# CHECK:   version 10.8
+# CHECK:   sdk n/a
+
+# NO_VERSION_MIN-NOT: LC_VERSION_MIN_MACOSX
\ No newline at end of file
diff --git a/test/mach-o/version-min-load-command.yaml b/test/mach-o/version-min-load-command.yaml
new file mode 100644 (file)
index 0000000..cb5331e
--- /dev/null
@@ -0,0 +1,43 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s --check-prefix=WARNING
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -sdk_version 10.9 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=SDK_VERSION
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK:   cmd LC_VERSION_MIN_MACOSX
+# CHECK:   cmdsize 16
+# CHECK:   version 10.8
+# CHECK:   sdk 10.8
+
+# SDK_VERSION: Load command {{[0-9]*}}
+# SDK_VERSION:   cmd LC_VERSION_MIN_MACOSX
+# SDK_VERSION:   cmdsize 16
+# SDK_VERSION:   version 10.8
+# SDK_VERSION:   sdk 10.9
+
+# WARNING: warning: -sdk_version is required when emitting min version load command.  Setting sdk version to match provided min version
+
+# NO_VERSION_MIN-NOT: LC_VERSION_MIN_MACOSX
diff --git a/test/mach-o/write-final-sections.yaml b/test/mach-o/write-final-sections.yaml
new file mode 100644 (file)
index 0000000..4e94acf
--- /dev/null
@@ -0,0 +1,165 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/write-final-sections.yaml \
+# RUN: -o %t -e _foo
+# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
+
+--- !native
+defined-atoms:
+# For __TEXT, __text (with typeCode)
+  - name:            _foo
+    scope:           global
+    content:         [ 55 ]
+# CHECK: Name: __text
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 55
+# CHECK-NEXT: )
+
+#  For __TEXT, __const (with typeConstant),
+  - type:            constant
+    content:         [ 01, 00, 00, 00 ]
+#  From __TEXT, __literal4, (with typeLiteral4)
+  - scope:           hidden
+    type:            const-4-byte
+    content:         [ 02, 00, 00, 00 ]
+#  From __TEXT, __literal8, (with typeLiteral8)
+  - scope:           hidden
+    type:            const-8-byte
+    content:         [ 03, 00, 00, 00, 00, 00, 00, 00 ]
+#  From __TEXT, __literal16, (with typeLiteral16)
+  - scope:           hidden
+    type:            const-16-byte
+    content:         [ 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __const
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 01000000 02000000 03000000 00000000
+# CHECK-NEXT: 0010: 04000000 00000000 00000000 00000000
+# CHECK-NEXT: )
+
+# For __TEXT, __cstring (with typeCString)
+  - scope:           hidden
+    type:            c-string
+    content:         [ 57, 69, 62, 62, 6C, 65, 00 ]
+    merge:           by-content
+# CHECK: Name: __cstring
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 57696262 6C6500
+# CHECK-NEXT: )
+
+# For __TEXT, __ustring (with typeUTF16String)
+  - scope:           hidden
+    type:            utf16-string
+    content:         [ 05, 00 ]
+    merge:           by-content
+# CHECK: Name: __ustring
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0500
+# CHECK-NEXT: )
+
+#  For __TEXT, __gcc_except_tab, (with typeLSDA)
+  - name:            GCC_except_table0
+    type:            unwind-lsda
+    content:         [ 06, 00 ]
+# CHECK: Name: __gcc_except_tab
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0600
+# CHECK-NEXT: )
+
+#  For __TEXT, __eh_frame, (with typeCFI)
+  - name:            LCIE
+    type:            unwind-cfi
+    content:         [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+                       01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+
+  - type:            unwind-cfi
+    content:         [ 24, 00, 00, 00, 1C, 00, 00, 00, C8, FE, FF, FF,
+                       FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+                       00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+                       00, 00, 00, 00 ]
+    references:
+      - kind:            unwindFDEToFunction
+        offset:          8
+        target:          _foo
+      - kind:            negDelta32
+        offset:          4
+        target:          LCIE
+
+# CHECK: Name: __eh_frame
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT:      0000: 14000000 00000000 017A5200 01781001
+# CHECK-NEXT:      0010: 100C0708 90010000 24000000 1C000000
+# CHECK-NEXT:      0020: 70FFFFFF FFFFFFFF 01000000 00000000
+# CHECK-NEXT:      0030: 00410E10 8602430D 06000000 00000000
+# CHECK-NEXT: )
+
+#  For __DATA, __data, (with typeData)
+  - name:            var
+    type:            data
+    content:         [ 08 ]
+# CHECK: Name: __data
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 08
+# CHECK-NEXT: )
+
+#  For __DATA, __bss (with typeZeroFill)
+# FIXME: Attributes & tags of __bss are mostly broken. Should be at end of
+#        __DATA, should have size, should have S_ZEROFILL flag.
+  - type:            zero-fill
+    size:            8
+# CHECK: Name: __bss
+# CHECK: Segment: __DATA
+
+#  For __DATA, __const, (with typeConstData)
+  - type:            const-data
+    content:         [ 09, 00, 00, 00 ]
+# CHECK: Name: __const
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 09000000
+# CHECK-NEXT: )
+
+#  For __DATA, __cfstring, (with typeCFString)
+  - type:            cfstring
+    content:         [ 0A, 00 ]
+# CHECK: Name: __cfstring
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0A00
+# CHECK-NEXT: )
+
+#  For __DATA, __got (with typeGOT)
+  - type:            got
+    content:         [ 0B, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __got
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0B000000 00000000
+# CHECK-NEXT: )
+
+
+#  For __DATA, __mod_init_func (with typeInitializerPtr)
+  - type:            initializer-pointer
+    content:         [ 0C, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __mod_init_func
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0C000000 00000000
+# CHECK-NEXT: )
+
+#  For __DATA, __mod_term_func (with typeTerminatorPointer)
+  - type:            terminator-pointer
+    content:         [ 0D, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __mod_term_func
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0D000000 00000000
+# CHECK-NEXT: )
+
+  - type:            compact-unwind
+    content:         [ 0E, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK-NOT: Name: __compact_unwind
diff --git a/test/mach-o/wrong-arch-error.yaml b/test/mach-o/wrong-arch-error.yaml
new file mode 100644 (file)
index 0000000..3b8ef0d
--- /dev/null
@@ -0,0 +1,28 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s \
+# RUN: %p/Inputs/wrong-arch-error.yaml 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0xCC ]
+
+global-symbols:
+  - name:            _foo
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+...
+
+
+# CHECK:       wrong architecture
diff --git a/tools/lld/CMakeLists.txt b/tools/lld/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2df1069
--- /dev/null
@@ -0,0 +1,24 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_lld_tool(lld
+  lld.cpp
+  )
+
+target_link_libraries(lld
+  lldDriver
+  lldCOFF
+  lldELF
+  )
+
+install(TARGETS lld
+  RUNTIME DESTINATION bin)
+
+if(NOT LLD_SYMLINKS_TO_CREATE)
+  set(LLD_SYMLINKS_TO_CREATE lld-link ld.lld)
+endif()
+
+foreach(link ${LLD_SYMLINKS_TO_CREATE})
+  add_lld_symlink(${link} lld)
+endforeach()
diff --git a/tools/lld/lld.cpp b/tools/lld/lld.cpp
new file mode 100644 (file)
index 0000000..09f8079
--- /dev/null
@@ -0,0 +1,113 @@
+//===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the lld driver. This is a thin wrapper which
+// dispatches to the given platform specific driver.
+//
+// If there is -flavor option, it is dispatched according to the arguments.
+// If the flavor parameter is not present, then it is dispatched according
+// to argv[0].
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+
+using namespace lld;
+using namespace llvm;
+using namespace llvm::sys;
+
+enum Flavor {
+  Invalid,
+  Gnu,     // -flavor gnu
+  WinLink, // -flavor link
+  Darwin,  // -flavor darwin
+};
+
+LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
+  errs() << S << "\n";
+  exit(1);
+}
+
+static Flavor getFlavor(StringRef S) {
+  return StringSwitch<Flavor>(S)
+      .CasesLower("ld", "ld.lld", "gnu", Gnu)
+      .CaseLower("link", WinLink)
+      .CaseLower("darwin", Darwin)
+      .Default(Invalid);
+}
+
+static Flavor parseProgname(StringRef Progname) {
+#if __APPLE__
+  // Use Darwin driver for "ld" on Darwin.
+  if (Progname == "ld")
+    return Darwin;
+#endif
+
+#if LLVM_ON_UNIX
+  // Use GNU driver for "ld" on other Unix-like system.
+  if (Progname == "ld")
+    return Gnu;
+#endif
+
+  // Progname may be something like "lld-gnu". Parse it.
+  SmallVector<StringRef, 3> V;
+  Progname.split(V, "-");
+  for (StringRef S : V)
+    if (Flavor F = getFlavor(S))
+      return F;
+  return Invalid;
+}
+
+static Flavor parseFlavor(std::vector<const char *> &V) {
+  // Parse -flavor option.
+  if (V.size() > 1 && V[1] == StringRef("-flavor")) {
+    if (V.size() <= 2)
+      die("missing arg value for '-flavor'");
+    Flavor F = getFlavor(V[2]);
+    if (F == Invalid)
+      die("Unknown flavor: " + StringRef(V[2]));
+    V.erase(V.begin() + 1, V.begin() + 3);
+    return F;
+  }
+
+  // Deduct the flavor from argv[0].
+  StringRef Arg0 = path::filename(V[0]);
+  if (Arg0.endswith_lower(".exe"))
+    Arg0 = Arg0.drop_back(4);
+  return parseProgname(Arg0);
+}
+
+/// Universal linker main(). This linker emulates the gnu, darwin, or
+/// windows linker based on the argv[0] or -flavor option.
+int main(int Argc, const char **Argv) {
+  // Standard set up, so program fails gracefully.
+  sys::PrintStackTraceOnErrorSignal(Argv[0]);
+  PrettyStackTraceProgram StackPrinter(Argc, Argv);
+  llvm_shutdown_obj Shutdown;
+
+  std::vector<const char *> Args(Argv, Argv + Argc);
+  switch (parseFlavor(Args)) {
+  case Gnu:
+    return !elf::link(Args, true);
+  case WinLink:
+    return !coff::link(Args);
+  case Darwin:
+    return !mach_o::link(Args);
+  default:
+    die("lld is a generic driver.\n"
+        "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead.");
+  }
+}
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..84d35d4
--- /dev/null
@@ -0,0 +1,16 @@
+add_custom_target(LLDUnitTests)
+set_target_properties(LLDUnitTests PROPERTIES FOLDER "lld tests")
+
+set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF)
+
+# add_lld_unittest(test_dirname file1.cpp file2.cpp)
+#
+# Will compile the list of files together and link against lld
+# Produces a binary named 'basename(test_dirname)'.
+function(add_lld_unittest test_dirname)
+  add_unittest(LLDUnitTests ${test_dirname} ${ARGN})
+  target_link_libraries(${test_dirname} ${LLVM_COMMON_LIBS})
+endfunction()
+
+add_subdirectory(DriverTests)
+add_subdirectory(MachOTests)
diff --git a/unittests/DriverTests/CMakeLists.txt b/unittests/DriverTests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..91d22ca
--- /dev/null
@@ -0,0 +1,8 @@
+add_lld_unittest(DriverTests
+  DarwinLdDriverTest.cpp
+  )
+
+target_link_libraries(DriverTests
+  lldDriver
+  lldMachO
+  )
diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp
new file mode 100644 (file)
index 0000000..d81f154
--- /dev/null
@@ -0,0 +1,267 @@
+//===- lld/unittest/DarwinLdDriverTest.cpp --------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Darwin's ld driver tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace lld;
+
+namespace lld {
+namespace mach_o {
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
+           raw_ostream &diagnostics);
+}
+}
+
+namespace {
+class DarwinLdParserTest : public testing::Test {
+protected:
+  int inputFileCount() { return _ctx.getNodes().size(); }
+
+  std::string inputFile(int index) {
+    Node &node = *_ctx.getNodes()[index];
+    if (node.kind() == Node::Kind::File)
+      return cast<FileNode>(&node)->getFile()->path();
+    llvm_unreachable("not handling other types of input files");
+  }
+
+  bool parse(std::vector<const char *> args) {
+    args.insert(args.begin(), "ld");
+    std::string errorMessage;
+    raw_string_ostream os(errorMessage);
+    return mach_o::parse(args, _ctx, os);
+  }
+
+  MachOLinkingContext _ctx;
+};
+}
+
+TEST_F(DarwinLdParserTest, Basic) {
+  EXPECT_TRUE(parse({"foo.o", "bar.o", "-arch", "i386"}));
+  EXPECT_FALSE(_ctx.allowRemainingUndefines());
+  EXPECT_FALSE(_ctx.deadStrip());
+  EXPECT_EQ(2, inputFileCount());
+  EXPECT_EQ("foo.o", inputFile(0));
+  EXPECT_EQ("bar.o", inputFile(1));
+}
+
+TEST_F(DarwinLdParserTest, Output) {
+  EXPECT_TRUE(parse({"-o", "my.out", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ("my.out", _ctx.outputPath());
+}
+
+TEST_F(DarwinLdParserTest, Dylib) {
+  EXPECT_TRUE(parse({"-dylib", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_DYLIB, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Relocatable) {
+  EXPECT_TRUE(parse({"-r", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_OBJECT, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Bundle) {
+  EXPECT_TRUE(parse({"-bundle", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_BUNDLE, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Preload) {
+  EXPECT_TRUE(parse({"-preload", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_PRELOAD, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Static) {
+  EXPECT_TRUE(parse({"-static", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ(llvm::MachO::MH_EXECUTE, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Entry) {
+  EXPECT_TRUE(parse({"-e", "entryFunc", "foo.o", "-arch", "i386"}));
+  EXPECT_EQ("entryFunc", _ctx.entrySymbolName());
+}
+
+TEST_F(DarwinLdParserTest, DeadStrip) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dead_strip", "foo.o"}));
+  EXPECT_TRUE(_ctx.deadStrip());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExe) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dead_strip", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsDylib) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dylib", "-dead_strip", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsRelocatable) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-r", "-dead_strip", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicExe) {
+  EXPECT_TRUE(
+      parse({"-arch", "x86_64", "-dead_strip", "-export_dynamic", "foo.o"}));
+  EXPECT_TRUE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicDylib) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "-dylib", "-dead_strip",
+                     "-export_dynamic", "foo.o"}));
+  EXPECT_TRUE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicRelocatable) {
+  EXPECT_TRUE(parse(
+      {"-arch", "x86_64", "-r", "-dead_strip", "-export_dynamic", "foo.o"}));
+  EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, Arch) {
+  EXPECT_TRUE(parse({"-arch", "x86_64", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_x86_64, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_X86_64, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_X86_64_ALL, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_x86) {
+  EXPECT_TRUE(parse({"-arch", "i386", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_x86, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_I386, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_X86_ALL, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv6) {
+  EXPECT_TRUE(parse({"-arch", "armv6", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_armv6, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V6, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv7) {
+  EXPECT_TRUE(parse({"-arch", "armv7", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_armv7, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V7, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv7s) {
+  EXPECT_TRUE(parse({"-arch", "armv7s", "foo.o"}));
+  EXPECT_EQ(MachOLinkingContext::arch_armv7s, _ctx.arch());
+  EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+  EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V7S, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, MinMacOSX10_7) {
+  EXPECT_TRUE(
+      parse({"-macosx_version_min", "10.7", "foo.o", "-arch", "x86_64"}));
+  EXPECT_EQ(MachOLinkingContext::OS::macOSX, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("10.7", ""));
+  EXPECT_FALSE(_ctx.minOS("10.8", ""));
+}
+
+TEST_F(DarwinLdParserTest, MinMacOSX10_8) {
+  EXPECT_TRUE(
+      parse({"-macosx_version_min", "10.8.3", "foo.o", "-arch", "x86_64"}));
+  EXPECT_EQ(MachOLinkingContext::OS::macOSX, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("10.7", ""));
+  EXPECT_TRUE(_ctx.minOS("10.8", ""));
+}
+
+TEST_F(DarwinLdParserTest, iOS5) {
+  EXPECT_TRUE(parse({"-ios_version_min", "5.0", "foo.o", "-arch", "armv7"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_FALSE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS6) {
+  EXPECT_TRUE(parse({"-ios_version_min", "6.0", "foo.o", "-arch", "armv7"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_TRUE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS_Simulator5) {
+  EXPECT_TRUE(
+      parse({"-ios_simulator_version_min", "5.0", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_FALSE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS_Simulator6) {
+  EXPECT_TRUE(
+      parse({"-ios_simulator_version_min", "6.0", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _ctx.os());
+  EXPECT_TRUE(_ctx.minOS("", "5.0"));
+  EXPECT_TRUE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersion) {
+  EXPECT_TRUE(parse(
+      {"-dylib", "-compatibility_version", "1.2.3", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(_ctx.compatibilityVersion(), 0x10203U);
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersionInvalidType) {
+  EXPECT_FALSE(parse(
+      {"-bundle", "-compatibility_version", "1.2.3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersionInvalidValue) {
+  EXPECT_FALSE(parse(
+      {"-bundle", "-compatibility_version", "1,2,3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, currentVersion) {
+  EXPECT_TRUE(
+      parse({"-dylib", "-current_version", "1.2.3", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(_ctx.currentVersion(), 0x10203U);
+}
+
+TEST_F(DarwinLdParserTest, currentVersionInvalidType) {
+  EXPECT_FALSE(
+      parse({"-bundle", "-current_version", "1.2.3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, currentVersionInvalidValue) {
+  EXPECT_FALSE(
+      parse({"-bundle", "-current_version", "1,2,3", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, bundleLoader) {
+  EXPECT_TRUE(
+      parse({"-bundle", "-bundle_loader", "/bin/ls", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(_ctx.bundleLoader(), "/bin/ls");
+}
+
+TEST_F(DarwinLdParserTest, bundleLoaderInvalidType) {
+  EXPECT_FALSE(parse({"-bundle_loader", "/bin/ls", "a.o", "-arch", "i386"}));
+}
+
+TEST_F(DarwinLdParserTest, deadStrippableDylib) {
+  EXPECT_TRUE(
+      parse({"-dylib", "-mark_dead_strippable_dylib", "a.o", "-arch", "i386"}));
+  EXPECT_EQ(true, _ctx.deadStrippableDylib());
+}
+
+TEST_F(DarwinLdParserTest, deadStrippableDylibInvalidType) {
+  EXPECT_FALSE(parse({"-mark_dead_strippable_dylib", "a.o", "-arch", "i386"}));
+}
diff --git a/unittests/MachOTests/CMakeLists.txt b/unittests/MachOTests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1a68348
--- /dev/null
@@ -0,0 +1,13 @@
+
+add_lld_unittest(lldMachOTests
+  MachONormalizedFileBinaryReaderTests.cpp
+  MachONormalizedFileBinaryWriterTests.cpp
+  MachONormalizedFileToAtomsTests.cpp
+  MachONormalizedFileYAMLTests.cpp
+  )
+
+target_link_libraries(lldMachOTests
+  lldDriver
+  lldMachO
+  lldYAML
+  )
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
new file mode 100644 (file)
index 0000000..3e8793a
--- /dev/null
@@ -0,0 +1,749 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryReaderTests.cpp ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "gtest/gtest.h"
+#include <cstdint>
+#include <memory>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+
+using namespace lld::mach_o::normalized;
+using namespace llvm::MachO;
+
+static std::unique_ptr<NormalizedFile>
+fromBinary(const uint8_t bytes[], unsigned length, StringRef archStr) {
+  StringRef sr((const char*)bytes, length);
+  std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(sr, "", false));
+  llvm::Expected<std::unique_ptr<NormalizedFile>> r =
+      lld::mach_o::normalized::readBinary(
+          mb, lld::MachOLinkingContext::archFromName(archStr));
+  EXPECT_FALSE(!r);
+  return std::move(*r);
+}
+
+// The Mach-O object reader uses functions such as read32 or read64
+// which don't allow unaligned access. Our in-memory object file
+// needs to be aligned to a larger boundary than uint8_t's.
+#if _MSC_VER
+#define FILEBYTES __declspec(align(64)) const uint8_t fileBytes[]
+#else
+#define FILEBYTES const uint8_t fileBytes[] __attribute__((aligned(64)))
+#endif
+
+TEST(BinaryReaderTest, empty_obj_x86_64) {
+  FILEBYTES = {
+      0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01,
+      0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x19, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_x86) {
+  FILEBYTES = {
+      0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00,
+      0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "i386");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_ppc) {
+  FILEBYTES = {
+      0xfe, 0xed, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x12,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c,
+      0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+      0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "ppc");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_armv7) {
+  FILEBYTES = {
+      0xce, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x00,
+      0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_x86_64_arm7) {
+  FILEBYTES = {
+#include "empty_obj_x86_armv7.txt"
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+
+  std::unique_ptr<NormalizedFile> f2 =
+      fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+  EXPECT_EQ(f2->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f2->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f2->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_TRUE(f2->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, hello_obj_x86_64) {
+  FILEBYTES = {
+    0xCF, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x01,
+    0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x19, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0xA4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x9D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0xB4, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0xE4, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0x0B, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+    0x48, 0x8D, 0x3D, 0x00, 0x00, 0x00, 0x00, 0xC7,
+    0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00,
+    0xE8, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00,
+    0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x48,
+    0x83, 0xC4, 0x10, 0x5D, 0xC3, 0x68, 0x65, 0x6C,
+    0x6C, 0x6F, 0x0A, 0x00, 0x19, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x2D, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x1D, 0x0F, 0x00, 0x00, 0x00,
+    0x0E, 0x02, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+    0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+    0x74, 0x66, 0x00, 0x4C, 0x5F, 0x2E, 0x73, 0x74,
+    0x72, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 45UL);
+  EXPECT_EQ((int)(text.content[0]), 0x55);
+  EXPECT_EQ((int)(text.content[1]), 0x48);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 2UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x19));
+  EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 2U);
+  const Relocation& str = text.relocations[1];
+  EXPECT_EQ(str.offset, Hex32(0xB));
+  EXPECT_EQ(str.type, X86_64_RELOC_SIGNED);
+  EXPECT_EQ(str.length, 2);
+  EXPECT_EQ(str.isExtern, true);
+  EXPECT_EQ(str.symbol, 0U);
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 1U);
+  EXPECT_EQ(cstring.address, Hex64(0x02D));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 1UL);
+  const Symbol& strLabel = f->localSymbols[0];
+  EXPECT_EQ(strLabel.type, N_SECT);
+  EXPECT_EQ(strLabel.sect, 2);
+  EXPECT_EQ(strLabel.value, Hex64(0x2D));
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+TEST(BinaryReaderTest, hello_obj_x86) {
+  FILEBYTES = {
+    0xCE, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x55, 0x89, 0xE5, 0x83,
+    0xEC, 0x18, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x58,
+    0x8D, 0x80, 0x25, 0x00, 0x00, 0x00, 0xC7, 0x45,
+    0xFC, 0x00, 0x00, 0x00, 0x00, 0x89, 0x04, 0x24,
+    0xE8, 0xDF, 0xFF, 0xFF, 0xFF, 0xB9, 0x00, 0x00,
+    0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x83,
+    0xC4, 0x18, 0x5D, 0xC3, 0x68, 0x65, 0x6C, 0x6C,
+    0x6F, 0x0A, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x0D, 0x0E, 0x00, 0x00, 0xA4,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1,
+    0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+    0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+    0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "i386");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 48UL);
+  EXPECT_EQ((int)(text.content[0]), 0x55);
+  EXPECT_EQ((int)(text.content[1]), 0x89);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 3UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1D));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(call.pcRel, true);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& sectDiff = text.relocations[1];
+  EXPECT_EQ(sectDiff.offset, Hex32(0xE));
+  EXPECT_EQ(sectDiff.scattered, true);
+  EXPECT_EQ(sectDiff.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(sectDiff.pcRel, false);
+  EXPECT_EQ(sectDiff.length, 2);
+  EXPECT_EQ(sectDiff.value, 0x30U);
+  const Relocation& pair = text.relocations[2];
+  EXPECT_EQ(pair.offset, Hex32(0x0));
+  EXPECT_EQ(pair.scattered, true);
+  EXPECT_EQ(pair.type, GENERIC_RELOC_PAIR);
+  EXPECT_EQ(pair.pcRel, false);
+  EXPECT_EQ(pair.length, 2);
+  EXPECT_EQ(pair.value, 0x0BU);
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 1U);
+  EXPECT_EQ(cstring.address, Hex64(0x030));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+TEST(BinaryReaderTest, hello_obj_armv7) {
+  FILEBYTES = {
+    0xCE, 0xFA, 0xED, 0xFE, 0x0C, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x31, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2A, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x6E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0xB5, 0x6F, 0x46,
+    0x82, 0xB0, 0x40, 0xF2, 0x18, 0x00, 0xC0, 0xF2,
+    0x00, 0x00, 0x78, 0x44, 0x00, 0x21, 0xC0, 0xF2,
+    0x00, 0x01, 0x01, 0x91, 0xFF, 0xF7, 0xF2, 0xFF,
+    0x00, 0x21, 0xC0, 0xF2, 0x00, 0x01, 0x00, 0x90,
+    0x08, 0x46, 0x02, 0xB0, 0x80, 0xBD, 0x68, 0x65,
+    0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x6D,
+    0x0A, 0x00, 0x00, 0xB9, 0x2A, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0xB1, 0x0E, 0x00, 0x00, 0x00,
+    0x06, 0x00, 0x00, 0xA9, 0x2A, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xA1, 0x0E, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+    0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 42UL);
+  EXPECT_EQ((int)(text.content[0]), 0x80);
+  EXPECT_EQ((int)(text.content[1]), 0xB5);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 5UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x18));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& movt = text.relocations[1];
+  EXPECT_EQ(movt.offset, Hex32(0xA));
+  EXPECT_EQ(movt.scattered, true);
+  EXPECT_EQ(movt.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movt.length, 3);
+  EXPECT_EQ(movt.value, Hex32(0x2A));
+  const Relocation& movtPair = text.relocations[2];
+  EXPECT_EQ(movtPair.offset, Hex32(0x18));
+  EXPECT_EQ(movtPair.scattered, true);
+  EXPECT_EQ(movtPair.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movtPair.length, 3);
+  EXPECT_EQ(movtPair.value, Hex32(0xE));
+  const Relocation& movw = text.relocations[3];
+  EXPECT_EQ(movw.offset, Hex32(0x6));
+  EXPECT_EQ(movw.scattered, true);
+  EXPECT_EQ(movw.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movw.length, 2);
+  EXPECT_EQ(movw.value, Hex32(0x2A));
+  const Relocation& movwPair = text.relocations[4];
+  EXPECT_EQ(movwPair.offset, Hex32(0x0));
+  EXPECT_EQ(movwPair.scattered, true);
+  EXPECT_EQ(movwPair.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movwPair.length, 2);
+  EXPECT_EQ(movwPair.value, Hex32(0xE));
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 1U);
+  EXPECT_EQ(cstring.address, Hex64(0x02A));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+TEST(BinaryReaderTest, hello_obj_ppc) {
+  FILEBYTES = {
+    0xFE, 0xED, 0xFA, 0xCE, 0x00, 0x00, 0x00, 0x12,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x28,
+    0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x01, 0x44,
+    0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x01, 0x44,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x90,
+    0x00, 0x00, 0x00, 0x05, 0x80, 0x00, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0xB8,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0xD0,
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0B,
+    0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x02, 0xA6,
+    0xBF, 0xC1, 0xFF, 0xF8, 0x90, 0x01, 0x00, 0x08,
+    0x94, 0x21, 0xFF, 0xB0, 0x7C, 0x3E, 0x0B, 0x78,
+    0x42, 0x9F, 0x00, 0x05, 0x7F, 0xE8, 0x02, 0xA6,
+    0x3C, 0x5F, 0x00, 0x00, 0x38, 0x62, 0x00, 0x2C,
+    0x4B, 0xFF, 0xFF, 0xDD, 0x38, 0x00, 0x00, 0x00,
+    0x7C, 0x03, 0x03, 0x78, 0x80, 0x21, 0x00, 0x00,
+    0x80, 0x01, 0x00, 0x08, 0x7C, 0x08, 0x03, 0xA6,
+    0xBB, 0xC1, 0xFF, 0xF8, 0x4E, 0x80, 0x00, 0x20,
+    0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x01, 0xD3,
+    0xAB, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x44,
+    0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+    0xAC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x44,
+    0xA1, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x18,
+    0x00, 0x00, 0x00, 0x01, 0x0F, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+    0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f =
+      fromBinary(fileBytes, sizeof(fileBytes), "ppc");
+
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(text.content.size(), 68UL);
+  EXPECT_EQ((int)(text.content[0]), 0x7C);
+  EXPECT_EQ((int)(text.content[1]), 0x08);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 5UL);
+  const Relocation& bl = text.relocations[0];
+  EXPECT_EQ(bl.offset, Hex32(0x24));
+  EXPECT_EQ(bl.type, PPC_RELOC_BR24);
+  EXPECT_EQ(bl.length, 2);
+  EXPECT_EQ(bl.isExtern, true);
+  EXPECT_EQ(bl.symbol, 1U);
+  const Relocation& lo = text.relocations[1];
+  EXPECT_EQ(lo.offset, Hex32(0x20));
+  EXPECT_EQ(lo.scattered, true);
+  EXPECT_EQ(lo.type, PPC_RELOC_LO16_SECTDIFF);
+  EXPECT_EQ(lo.length, 2);
+  EXPECT_EQ(lo.value, Hex32(0x44));
+  const Relocation& loPair = text.relocations[2];
+  EXPECT_EQ(loPair.offset, Hex32(0x0));
+  EXPECT_EQ(loPair.scattered, true);
+  EXPECT_EQ(loPair.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(loPair.length, 2);
+  EXPECT_EQ(loPair.value, Hex32(0x18));
+  const Relocation& ha = text.relocations[3];
+  EXPECT_EQ(ha.offset, Hex32(0x1C));
+  EXPECT_EQ(ha.scattered, true);
+  EXPECT_EQ(ha.type, PPC_RELOC_HA16_SECTDIFF);
+  EXPECT_EQ(ha.length, 2);
+  EXPECT_EQ(ha.value, Hex32(0x44));
+  const Relocation& haPair = text.relocations[4];
+  EXPECT_EQ(haPair.offset, Hex32(0x2c));
+  EXPECT_EQ(haPair.scattered, true);
+  EXPECT_EQ(haPair.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(haPair.length, 2);
+  EXPECT_EQ(haPair.value, Hex32(0x18));
+
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ((uint16_t)cstring.alignment, 4U);
+  EXPECT_EQ(cstring.address, Hex64(0x044));
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+
+  auto ec = writeBinary(*f, "/tmp/foo.o");
+  // FIXME: We want to do EXPECT_FALSE(ec) but that fails on some Windows bots,
+  // probably due to /tmp not being available.
+  // For now just consume the error without checking it.
+  consumeError(std::move(ec));
+}
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp
new file mode 100644 (file)
index 0000000..210fecb
--- /dev/null
@@ -0,0 +1,696 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryWriterTests.cpp ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/FileSystem.h"
+#include "gtest/gtest.h"
+#include <cassert>
+#include <memory>
+#include <system_error>
+#include <vector>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using llvm::SmallString;
+using llvm::Twine;
+using llvm::ErrorOr;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+// Parses binary mach-o file at specified path and returns
+// ownership of buffer to mb parameter and ownership of
+// Normalized file to nf parameter.
+static void fromBinary(StringRef path, std::unique_ptr<MemoryBuffer> &mb,
+                       std::unique_ptr<NormalizedFile> &nf, StringRef archStr) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(path);
+  std::error_code ec = mbOrErr.getError();
+  EXPECT_FALSE(ec);
+  mb = std::move(mbOrErr.get());
+
+  llvm::Expected<std::unique_ptr<NormalizedFile>> r =
+      lld::mach_o::normalized::readBinary(
+          mb, lld::MachOLinkingContext::archFromName(archStr));
+  EXPECT_FALSE(!r);
+  nf.reset(r->release());
+}
+
+static Relocation
+makeReloc(unsigned addr, bool rel, bool ext, RelocationInfoType type,
+                                                              unsigned sym) {
+  Relocation result;
+  result.offset = addr;
+  result.scattered = false;
+  result.type = type;
+  result.length = 2;
+  result.pcRel = rel;
+  result.isExtern = ext;
+  result.value = 0;
+  result.symbol = sym;
+  return result;
+}
+
+static Relocation
+makeScatReloc(unsigned addr, RelocationInfoType type, unsigned value) {
+  Relocation result;
+  result.offset = addr;
+  result.scattered = true;
+  result.type = type;
+  result.length = 2;
+  result.pcRel = false;
+  result.isExtern = true;
+  result.value = value;
+  result.symbol = 0;
+  return result;
+}
+
+static Symbol
+makeUndefSymbol(StringRef name) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_UNDF;
+  sym.scope = N_EXT;
+  sym.sect = NO_SECT;
+  sym.desc = 0;
+  sym.value = 0;
+  return sym;
+}
+
+
+static Symbol
+makeSymbol(StringRef name, unsigned addr) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_SECT;
+  sym.scope = N_EXT;
+  sym.sect = 1;
+  sym.desc = 0;
+  sym.value = addr;
+  return sym;
+}
+
+static Symbol
+makeThumbSymbol(StringRef name, unsigned addr) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_SECT;
+  sym.scope = N_EXT;
+  sym.sect = 1;
+  sym.desc = N_ARM_THUMB_DEF;
+  sym.value = addr;
+  return sym;
+}
+
+TEST(BinaryWriterTest, obj_relocs_x86_64) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86_64;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 16;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0xe8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x05,
+      0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00,
+      0x00, 0x00, 0x8b, 0x05, 0x00, 0x00, 0x00, 0x00,
+      0xc6, 0x05, 0xff, 0xff, 0xff, 0xff, 0x12, 0xc7,
+      0x05, 0xfc, 0xff, 0xff, 0xff, 0x78, 0x56, 0x34,
+      0x12, 0x48, 0x8b, 0x3d, 0x00, 0x00, 0x00, 0x00 };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x01, false, true, X86_64_RELOC_BRANCH, 1));
+    text.relocations.push_back(makeReloc(0x08, false, true, X86_64_RELOC_GOT_LOAD, 1));
+    text.relocations.push_back(makeReloc(0x0E, false, true, X86_64_RELOC_GOT, 1));
+    text.relocations.push_back(makeReloc(0x14, false, true, X86_64_RELOC_SIGNED, 1));
+    text.relocations.push_back(makeReloc(0x1A, false, true, X86_64_RELOC_SIGNED_1, 1));
+    text.relocations.push_back(makeReloc(0x21, false, true, X86_64_RELOC_SIGNED_4, 1));
+    text.relocations.push_back(makeReloc(0x2C, false, true, X86_64_RELOC_TLV, 2));
+
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "x86_64");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_x86_64, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  const Symbol& tbarUndef = f2->undefinedSymbols[1];
+  EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+  EXPECT_EQ(N_UNDF, tbarUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(48UL, text.content.size());
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1));
+  EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& gotLoad = text.relocations[1];
+  EXPECT_EQ(gotLoad.offset, Hex32(0x8));
+  EXPECT_EQ(gotLoad.type, X86_64_RELOC_GOT_LOAD);
+  EXPECT_EQ(gotLoad.length, 2);
+  EXPECT_EQ(gotLoad.isExtern, true);
+  EXPECT_EQ(gotLoad.symbol, 1U);
+  const Relocation& gotUse = text.relocations[2];
+  EXPECT_EQ(gotUse.offset, Hex32(0xE));
+  EXPECT_EQ(gotUse.type, X86_64_RELOC_GOT);
+  EXPECT_EQ(gotUse.length, 2);
+  EXPECT_EQ(gotUse.isExtern, true);
+  EXPECT_EQ(gotUse.symbol, 1U);
+  const Relocation& signed0 = text.relocations[3];
+  EXPECT_EQ(signed0.offset, Hex32(0x14));
+  EXPECT_EQ(signed0.type, X86_64_RELOC_SIGNED);
+  EXPECT_EQ(signed0.length, 2);
+  EXPECT_EQ(signed0.isExtern, true);
+  EXPECT_EQ(signed0.symbol, 1U);
+  const Relocation& signed1 = text.relocations[4];
+  EXPECT_EQ(signed1.offset, Hex32(0x1A));
+  EXPECT_EQ(signed1.type, X86_64_RELOC_SIGNED_1);
+  EXPECT_EQ(signed1.length, 2);
+  EXPECT_EQ(signed1.isExtern, true);
+  EXPECT_EQ(signed1.symbol, 1U);
+  const Relocation& signed4 = text.relocations[5];
+  EXPECT_EQ(signed4.offset, Hex32(0x21));
+  EXPECT_EQ(signed4.type, X86_64_RELOC_SIGNED_4);
+  EXPECT_EQ(signed4.length, 2);
+  EXPECT_EQ(signed4.isExtern, true);
+  EXPECT_EQ(signed4.symbol, 1U);
+
+  bufferOwner.reset(nullptr);
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_x86) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 16;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+       0xe8, 0xfb, 0xff, 0xff, 0xff, 0xa1, 0x00, 0x00,
+       0x00, 0x00, 0x8b, 0xb0, 0xfb, 0xff, 0xff, 0xff,
+       0x8b, 0x80, 0x11, 0x00, 0x00, 0x00 };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x01, true, true, GENERIC_RELOC_VANILLA, 0));
+    text.relocations.push_back(makeReloc(0x06, false, true, GENERIC_RELOC_VANILLA, 0));
+    text.relocations.push_back(makeScatReloc(0x0c, GENERIC_RELOC_LOCAL_SECTDIFF, 0));
+    text.relocations.push_back(makeScatReloc(0x0, GENERIC_RELOC_PAIR, 5));
+    text.relocations.push_back(makeReloc(0x12, true, true, GENERIC_RELOC_TLV, 1));
+
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "i386");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_x86, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  const Symbol& tbarUndef = f2->undefinedSymbols[1];
+  EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+  EXPECT_EQ(N_UNDF, tbarUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 16U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(22UL, text.content.size());
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(call.pcRel, true);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 0U);
+  const Relocation& absLoad = text.relocations[1];
+  EXPECT_EQ(absLoad.offset, Hex32(0x6));
+  EXPECT_EQ(absLoad.scattered, false);
+  EXPECT_EQ(absLoad.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(absLoad.pcRel, false);
+  EXPECT_EQ(absLoad.length, 2);
+  EXPECT_EQ(absLoad.isExtern, true);
+  EXPECT_EQ(absLoad.symbol,0U);
+  const Relocation& pic1 = text.relocations[2];
+  EXPECT_EQ(pic1.offset, Hex32(0xc));
+  EXPECT_EQ(pic1.scattered, true);
+  EXPECT_EQ(pic1.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(pic1.length, 2);
+  EXPECT_EQ(pic1.value, 0U);
+  const Relocation& pic2 = text.relocations[3];
+  EXPECT_EQ(pic2.offset, Hex32(0x0));
+  EXPECT_EQ(pic1.scattered, true);
+  EXPECT_EQ(pic2.type, GENERIC_RELOC_PAIR);
+  EXPECT_EQ(pic2.length, 2);
+  EXPECT_EQ(pic2.value, 5U);
+  const Relocation& tlv = text.relocations[4];
+  EXPECT_EQ(tlv.offset, Hex32(0x12));
+  EXPECT_EQ(tlv.type, GENERIC_RELOC_TLV);
+  EXPECT_EQ(tlv.length, 2);
+  EXPECT_EQ(tlv.isExtern, true);
+  EXPECT_EQ(tlv.symbol, 1U);
+
+  //llvm::errs() << "temp = " << tmpFl << "\n";
+  bufferOwner.reset(nullptr);
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_armv7) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_armv7;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 4;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0xff, 0xf7, 0xfe, 0xef, 0x40, 0xf2, 0x05, 0x01,
+      0xc0, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0xbf };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x00, true, true,
+                                        ARM_THUMB_RELOC_BR22, 2));
+    text.relocations.push_back(makeScatReloc(0x04,
+                                        ARM_RELOC_HALF_SECTDIFF, 0x10));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        ARM_RELOC_PAIR, 0xC));
+    text.relocations.push_back(makeScatReloc(0x08,
+                                        ARM_RELOC_HALF_SECTDIFF, 0x10));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        ARM_RELOC_PAIR, 0xC));
+    text.relocations.push_back(makeReloc(0x0C, false, true,
+                                        ARM_RELOC_VANILLA, 2));
+
+    f.globalSymbols.push_back(makeThumbSymbol("_foo", 0x00));
+    f.globalSymbols.push_back(makeThumbSymbol("_foo2", 0x10));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "armv7");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_armv7, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_EQ(2UL, f2->globalSymbols.size());
+  const Symbol& fooDef = f2->globalSymbols[0];
+  EXPECT_TRUE(fooDef.name.equals("_foo"));
+  EXPECT_EQ(N_SECT, fooDef.type);
+  EXPECT_EQ(1, fooDef.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+  const Symbol& foo2Def = f2->globalSymbols[1];
+  EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+  EXPECT_EQ(N_SECT, foo2Def.type);
+  EXPECT_EQ(1, foo2Def.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+
+  EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(18UL, text.content.size());
+  const Relocation& blx = text.relocations[0];
+  EXPECT_EQ(blx.offset, Hex32(0x0));
+  EXPECT_EQ(blx.scattered, false);
+  EXPECT_EQ(blx.type, ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(blx.pcRel, true);
+  EXPECT_EQ(blx.length, 2);
+  EXPECT_EQ(blx.isExtern, true);
+  EXPECT_EQ(blx.symbol, 2U);
+  const Relocation& movw1 = text.relocations[1];
+  EXPECT_EQ(movw1.offset, Hex32(0x4));
+  EXPECT_EQ(movw1.scattered, true);
+  EXPECT_EQ(movw1.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movw1.length, 2);
+  EXPECT_EQ(movw1.value, 0x10U);
+  const Relocation& movw2 = text.relocations[2];
+  EXPECT_EQ(movw2.offset, Hex32(0x0));
+  EXPECT_EQ(movw2.scattered, true);
+  EXPECT_EQ(movw2.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movw2.length, 2);
+  EXPECT_EQ(movw2.value, Hex32(0xC));
+   const Relocation& movt1 = text.relocations[3];
+  EXPECT_EQ(movt1.offset, Hex32(0x8));
+  EXPECT_EQ(movt1.scattered, true);
+  EXPECT_EQ(movt1.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movt1.length, 2);
+  EXPECT_EQ(movt1.value, Hex32(0x10));
+  const Relocation& movt2 = text.relocations[4];
+  EXPECT_EQ(movt2.offset, Hex32(0x0));
+  EXPECT_EQ(movt2.scattered, true);
+  EXPECT_EQ(movt2.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movt2.length, 2);
+  EXPECT_EQ(movt2.value, Hex32(0xC));
+ const Relocation& absPointer = text.relocations[5];
+  EXPECT_EQ(absPointer.offset, Hex32(0xC));
+  EXPECT_EQ(absPointer.type, ARM_RELOC_VANILLA);
+  EXPECT_EQ(absPointer.length, 2);
+  EXPECT_EQ(absPointer.isExtern, true);
+  EXPECT_EQ(absPointer.symbol, 2U);
+
+  //llvm::errs() << "temp = " << tmpFl << "\n";
+  bufferOwner.reset(nullptr);
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_ppc) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_ppc;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 4;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0x48, 0x00, 0x00, 0x01, 0x40, 0x82, 0xff, 0xfc,
+      0x3c, 0x62, 0x00, 0x00, 0x3c, 0x62, 0x00, 0x00,
+      0x80, 0x63, 0x00, 0x24, 0x80, 0x63, 0x00, 0x24,
+      0x3c, 0x40, 0x00, 0x00, 0x3c, 0x60, 0x00, 0x00,
+      0x80, 0x42, 0x00, 0x28, 0x80, 0x63, 0x00, 0x28,
+      0x60, 0x00, 0x00, 0x00 };
+
+    text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x00, true, true,
+                                        PPC_RELOC_BR24, 2));
+    text.relocations.push_back(makeReloc(0x04, true, true,
+                                        PPC_RELOC_BR14, 2));
+    text.relocations.push_back(makeScatReloc(0x08,
+                                        PPC_RELOC_HI16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x24,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x0C,
+                                        PPC_RELOC_HA16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x24,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x10,
+                                        PPC_RELOC_LO16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x14,
+                                        PPC_RELOC_LO14_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x00,
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeReloc(0x18, false, false,
+                                        PPC_RELOC_HI16, 1));
+    text.relocations.push_back(makeReloc(0x28, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x1C, false, false,
+                                        PPC_RELOC_HA16, 1));
+    text.relocations.push_back(makeReloc(0x28, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x20, false, false,
+                                        PPC_RELOC_LO16, 1));
+    text.relocations.push_back(makeReloc(0x00, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x24, false, false,
+                                        PPC_RELOC_LO14, 1));
+    text.relocations.push_back(makeReloc(0x00, false, false,
+                                        PPC_RELOC_PAIR, 0));
+
+    f.globalSymbols.push_back(makeSymbol("_foo", 0x00));
+    f.globalSymbols.push_back(makeSymbol("_foo2", 0x28));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+    std::error_code ec =
+        llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    llvm::Error ec2 = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec2);
+  }
+  std::unique_ptr<MemoryBuffer> bufferOwner;
+  std::unique_ptr<NormalizedFile> f2;
+  fromBinary(tmpFl, bufferOwner, f2, "ppc");
+
+  EXPECT_EQ(lld::MachOLinkingContext::arch_ppc, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_EQ(2UL, f2->globalSymbols.size());
+  const Symbol& fooDef = f2->globalSymbols[0];
+  EXPECT_TRUE(fooDef.name.equals("_foo"));
+  EXPECT_EQ(N_SECT, fooDef.type);
+  EXPECT_EQ(1, fooDef.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+  const Symbol& foo2Def = f2->globalSymbols[1];
+  EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+  EXPECT_EQ(N_SECT, foo2Def.type);
+  EXPECT_EQ(1, foo2Def.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+
+  EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)text.alignment, 4U);
+  EXPECT_EQ(text.address, Hex64(0x0));
+  EXPECT_EQ(44UL, text.content.size());
+  const Relocation& br24 = text.relocations[0];
+  EXPECT_EQ(br24.offset, Hex32(0x0));
+  EXPECT_EQ(br24.scattered, false);
+  EXPECT_EQ(br24.type, PPC_RELOC_BR24);
+  EXPECT_EQ(br24.pcRel, true);
+  EXPECT_EQ(br24.length, 2);
+  EXPECT_EQ(br24.isExtern, true);
+  EXPECT_EQ(br24.symbol, 2U);
+  const Relocation& br14 = text.relocations[1];
+  EXPECT_EQ(br14.offset, Hex32(0x4));
+  EXPECT_EQ(br14.scattered, false);
+  EXPECT_EQ(br14.type, PPC_RELOC_BR14);
+  EXPECT_EQ(br14.pcRel, true);
+  EXPECT_EQ(br14.length, 2);
+  EXPECT_EQ(br14.isExtern, true);
+  EXPECT_EQ(br14.symbol, 2U);
+  const Relocation& pichi1 = text.relocations[2];
+  EXPECT_EQ(pichi1.offset, Hex32(0x8));
+  EXPECT_EQ(pichi1.scattered, true);
+  EXPECT_EQ(pichi1.type, PPC_RELOC_HI16_SECTDIFF);
+  EXPECT_EQ(pichi1.length, 2);
+  EXPECT_EQ(pichi1.value, 0x28U);
+  const Relocation& pichi2 = text.relocations[3];
+  EXPECT_EQ(pichi2.offset, Hex32(0x24));
+  EXPECT_EQ(pichi2.scattered, true);
+  EXPECT_EQ(pichi2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(pichi2.length, 2);
+  EXPECT_EQ(pichi2.value, 0x4U);
+  const Relocation& picha1 = text.relocations[4];
+  EXPECT_EQ(picha1.offset, Hex32(0xC));
+  EXPECT_EQ(picha1.scattered, true);
+  EXPECT_EQ(picha1.type, PPC_RELOC_HA16_SECTDIFF);
+  EXPECT_EQ(picha1.length, 2);
+  EXPECT_EQ(picha1.value, 0x28U);
+  const Relocation& picha2 = text.relocations[5];
+  EXPECT_EQ(picha2.offset, Hex32(0x24));
+  EXPECT_EQ(picha2.scattered, true);
+  EXPECT_EQ(picha2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(picha2.length, 2);
+  EXPECT_EQ(picha2.value, 0x4U);
+  const Relocation& piclo1 = text.relocations[6];
+  EXPECT_EQ(piclo1.offset, Hex32(0x10));
+  EXPECT_EQ(piclo1.scattered, true);
+  EXPECT_EQ(piclo1.type, PPC_RELOC_LO16_SECTDIFF);
+  EXPECT_EQ(piclo1.length, 2);
+  EXPECT_EQ(piclo1.value, 0x28U);
+  const Relocation& piclo2 = text.relocations[7];
+  EXPECT_EQ(piclo2.offset, Hex32(0x0));
+  EXPECT_EQ(piclo2.scattered, true);
+  EXPECT_EQ(piclo2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(piclo2.length, 2);
+  EXPECT_EQ(piclo2.value, 0x4U);
+  const Relocation& picloa1 = text.relocations[8];
+  EXPECT_EQ(picloa1.offset, Hex32(0x14));
+  EXPECT_EQ(picloa1.scattered, true);
+  EXPECT_EQ(picloa1.type, PPC_RELOC_LO14_SECTDIFF);
+  EXPECT_EQ(picloa1.length, 2);
+  EXPECT_EQ(picloa1.value, 0x28U);
+  const Relocation& picloa2 = text.relocations[9];
+  EXPECT_EQ(picloa2.offset, Hex32(0x0));
+  EXPECT_EQ(picloa2.scattered, true);
+  EXPECT_EQ(picloa2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(picloa2.length, 2);
+  EXPECT_EQ(picloa2.value, 0x4U);
+  const Relocation& abshi1 = text.relocations[10];
+  EXPECT_EQ(abshi1.offset, Hex32(0x18));
+  EXPECT_EQ(abshi1.scattered, false);
+  EXPECT_EQ(abshi1.type, PPC_RELOC_HI16);
+  EXPECT_EQ(abshi1.length, 2);
+  EXPECT_EQ(abshi1.symbol, 1U);
+  const Relocation& abshi2 = text.relocations[11];
+  EXPECT_EQ(abshi2.offset, Hex32(0x28));
+  EXPECT_EQ(abshi2.scattered, false);
+  EXPECT_EQ(abshi2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(abshi2.length, 2);
+  EXPECT_EQ(abshi2.symbol, 0U);
+  const Relocation& absha1 = text.relocations[12];
+  EXPECT_EQ(absha1.offset, Hex32(0x1C));
+  EXPECT_EQ(absha1.scattered, false);
+  EXPECT_EQ(absha1.type, PPC_RELOC_HA16);
+  EXPECT_EQ(absha1.length, 2);
+  EXPECT_EQ(absha1.symbol, 1U);
+  const Relocation& absha2 = text.relocations[13];
+  EXPECT_EQ(absha2.offset, Hex32(0x28));
+  EXPECT_EQ(absha2.scattered, false);
+  EXPECT_EQ(absha2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(absha2.length, 2);
+  EXPECT_EQ(absha2.symbol, 0U);
+  const Relocation& abslo1 = text.relocations[14];
+  EXPECT_EQ(abslo1.offset, Hex32(0x20));
+  EXPECT_EQ(abslo1.scattered, false);
+  EXPECT_EQ(abslo1.type, PPC_RELOC_LO16);
+  EXPECT_EQ(abslo1.length, 2);
+  EXPECT_EQ(abslo1.symbol, 1U);
+  const Relocation& abslo2 = text.relocations[15];
+  EXPECT_EQ(abslo2.offset, Hex32(0x00));
+  EXPECT_EQ(abslo2.scattered, false);
+  EXPECT_EQ(abslo2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(abslo2.length, 2);
+  EXPECT_EQ(abslo2.symbol, 0U);
+  const Relocation& absloa1 = text.relocations[16];
+  EXPECT_EQ(absloa1.offset, Hex32(0x24));
+  EXPECT_EQ(absloa1.scattered, false);
+  EXPECT_EQ(absloa1.type, PPC_RELOC_LO14);
+  EXPECT_EQ(absloa1.length, 2);
+  EXPECT_EQ(absloa1.symbol, 1U);
+  const Relocation& absloa2 = text.relocations[17];
+  EXPECT_EQ(absloa2.offset, Hex32(0x00));
+  EXPECT_EQ(absloa2.scattered, false);
+  EXPECT_EQ(absloa2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(absloa2.length, 2);
+  EXPECT_EQ(absloa2.symbol, 0U);
+
+  bufferOwner.reset(nullptr);
+  std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
diff --git a/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp
new file mode 100644 (file)
index 0000000..a0176bb
--- /dev/null
@@ -0,0 +1,100 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileToAtomsTests.cpp --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "gtest/gtest.h"
+#include <cstdint>
+#include <memory>
+
+using namespace lld::mach_o::normalized;
+using namespace llvm::MachO;
+
+TEST(ToAtomsTest, empty_obj_x86_64) {
+  NormalizedFile f;
+  f.arch = lld::MachOLinkingContext::arch_x86_64;
+  llvm::Expected<std::unique_ptr<const lld::File>> atom_f =
+      normalizedToAtoms(f, "", false);
+  EXPECT_FALSE(!atom_f);
+  EXPECT_EQ(0U, (*atom_f)->defined().size());
+}
+
+TEST(ToAtomsTest, basic_obj_x86_64) {
+  NormalizedFile f;
+  f.arch = lld::MachOLinkingContext::arch_x86_64;
+  Section textSection;
+  static const uint8_t contentBytes[] = { 0x90, 0xC3, 0xC3, 0xC4 };
+  const unsigned contentSize = sizeof(contentBytes) / sizeof(contentBytes[0]);
+  textSection.content = llvm::makeArrayRef(contentBytes, contentSize);
+  f.sections.push_back(textSection);
+  Symbol fooSymbol;
+  fooSymbol.name = "_foo";
+  fooSymbol.type = N_SECT;
+  fooSymbol.scope = N_EXT;
+  fooSymbol.sect = 1;
+  fooSymbol.value = 0;
+  f.globalSymbols.push_back(fooSymbol);
+  Symbol barSymbol;
+  barSymbol.name = "_bar";
+  barSymbol.type = N_SECT;
+  barSymbol.scope = N_EXT;
+  barSymbol.sect = 1;
+  barSymbol.value = 2;
+  f.globalSymbols.push_back(barSymbol);
+  Symbol undefSym;
+  undefSym.name = "_undef";
+  undefSym.type = N_UNDF;
+  f.undefinedSymbols.push_back(undefSym);
+  Symbol bazSymbol;
+  bazSymbol.name = "_baz";
+  bazSymbol.type = N_SECT;
+  bazSymbol.scope = N_EXT | N_PEXT;
+  bazSymbol.sect = 1;
+  bazSymbol.value = 3;
+  f.localSymbols.push_back(bazSymbol);
+
+  llvm::Expected<std::unique_ptr<const lld::File>> atom_f =
+      normalizedToAtoms(f, "", false);
+  EXPECT_FALSE(!atom_f);
+  const lld::File &file = **atom_f;
+  EXPECT_EQ(3U, file.defined().size());
+  auto it = file.defined().begin();
+  const lld::DefinedAtom *atom1 = *it;
+  ++it;
+  const lld::DefinedAtom *atom2 = *it;
+  ++it;
+  const lld::DefinedAtom *atom3 = *it;
+  const lld::UndefinedAtom *atom4 = *file.undefined().begin();
+  EXPECT_TRUE(atom1->name().equals("_foo"));
+  EXPECT_EQ(2U, atom1->rawContent().size());
+  EXPECT_EQ(0x90, atom1->rawContent()[0]);
+  EXPECT_EQ(0xC3, atom1->rawContent()[1]);
+  EXPECT_EQ(lld::Atom::scopeGlobal, atom1->scope());
+
+  EXPECT_TRUE(atom2->name().equals("_bar"));
+  EXPECT_EQ(1U, atom2->rawContent().size());
+  EXPECT_EQ(0xC3, atom2->rawContent()[0]);
+  EXPECT_EQ(lld::Atom::scopeGlobal, atom2->scope());
+
+  EXPECT_TRUE(atom3->name().equals("_baz"));
+  EXPECT_EQ(1U, atom3->rawContent().size());
+  EXPECT_EQ(0xC4, atom3->rawContent()[0]);
+  EXPECT_EQ(lld::Atom::scopeLinkageUnit, atom3->scope());
+
+  EXPECT_TRUE(atom4->name().equals("_undef"));
+  EXPECT_EQ(lld::Atom::definitionUndefined, atom4->definition());
+}
diff --git a/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp
new file mode 100644 (file)
index 0000000..6bbde72
--- /dev/null
@@ -0,0 +1,763 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileYAMLTests.cpp -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <system_error>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using lld::mach_o::normalized::NormalizedFile;
+using lld::mach_o::normalized::Symbol;
+using lld::mach_o::normalized::Section;
+using lld::mach_o::normalized::Relocation;
+
+static std::unique_ptr<NormalizedFile> fromYAML(StringRef str) {
+  std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(str));
+  llvm::Expected<std::unique_ptr<NormalizedFile>> r
+                                    = lld::mach_o::normalized::readYaml(mb);
+  EXPECT_FALSE(!r);
+  return std::move(*r);
+}
+
+static void toYAML(const NormalizedFile &f, std::string &out) {
+  llvm::raw_string_ostream ostr(out);
+  std::error_code ec = lld::mach_o::normalized::writeYaml(f, ostr);
+  EXPECT_TRUE(!ec);
+}
+
+// ppc is no longer supported, but it is here to test endianness handling.
+TEST(ObjectFileYAML, empty_ppc) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      ppc\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86_64) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv6) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv6\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7s) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7s\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7s);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, roundTrip) {
+  std::string intermediate;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86_64;
+    f.fileType = llvm::MachO::MH_OBJECT;
+    f.flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    toYAML(f, intermediate);
+  }
+  {
+    std::unique_ptr<NormalizedFile> f2 = fromYAML(intermediate);
+    EXPECT_EQ(f2->arch, lld::MachOLinkingContext::arch_x86_64);
+    EXPECT_EQ((int)(f2->fileType), llvm::MachO::MH_OBJECT);
+    EXPECT_EQ((int)(f2->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+    EXPECT_TRUE(f2->sections.empty());
+    EXPECT_TRUE(f2->localSymbols.empty());
+    EXPECT_TRUE(f2->globalSymbols.empty());
+    EXPECT_TRUE(f2->undefinedSymbols.empty());
+  }
+}
+
+TEST(ObjectFileYAML, oneSymbol) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    desc:   [ ]\n"
+    "    value:  0x100\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym = f->globalSymbols[0];
+  EXPECT_TRUE(sym.name.equals("_main"));
+  EXPECT_EQ((int)(sym.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym.sect, 1);
+  EXPECT_EQ((int)(sym.desc), 0);
+  EXPECT_EQ((uint64_t)sym.value, 0x100ULL);
+}
+
+TEST(ObjectFileYAML, oneSection) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS ]\n"
+    "    alignment:   2\n"
+    "    address:     0x12345678\n"
+    "    content:     [ 0x90, 0x90 ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+  EXPECT_EQ(f->sections.size(), 1UL);
+  const Section& sect = f->sections[0];
+  EXPECT_TRUE(sect.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect.alignment, 2U);
+  EXPECT_EQ((uint64_t)sect.address, 0x12345678ULL);
+  EXPECT_EQ(sect.content.size(), 2UL);
+  EXPECT_EQ((int)(sect.content[0]), 0x90);
+  EXPECT_EQ((int)(sect.content[1]), 0x90);
+}
+
+TEST(ObjectFileYAML, hello_x86_64) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   1\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x55, 0x48, 0x89, 0xe5, 0x48, 0x8d, 0x3d, 0x00,\n"
+    "                   0x00, 0x00, 0x00, 0x30, 0xc0, 0xe8, 0x00, 0x00,\n"
+    "                   0x00, 0x00, 0x31, 0xc0, 0x5d, 0xc3 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x0e\n"
+    "       type:       X86_64_RELOC_BRANCH\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     2\n"
+    "     - offset:     0x07\n"
+    "       type:       X86_64_RELOC_SIGNED\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0016\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "local-symbols:\n"
+    "  - name:   L_.str\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ ]\n"
+    "    sect:   2\n"
+    "    value:  0x16\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 22UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x55);
+  EXPECT_EQ((int)(sect1.content[1]), 0x48);
+  EXPECT_EQ(sect1.relocations.size(), 2UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x0eU);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::X86_64_RELOC_BRANCH);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 2U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x07U);
+  EXPECT_FALSE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::X86_64_RELOC_SIGNED);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_TRUE(reloc2.pcRel);
+  EXPECT_TRUE(reloc2.isExtern);
+  EXPECT_EQ(reloc2.symbol, 1U);
+  EXPECT_EQ((int)(reloc2.value), 0);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x016ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->localSymbols.size(), 1UL);
+  const Symbol& sym2 = f->localSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("L_.str"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 2);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x16ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym3 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym3.name.equals("_printf"));
+  EXPECT_EQ((int)(sym3.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym3.scope), 0);
+  EXPECT_EQ(sym3.sect, 0);
+  EXPECT_EQ((int)(sym3.desc), 0);
+  EXPECT_EQ((uint64_t)sym3.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_x86) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   1\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x55, 0x89, 0xe5, 0x83, 0xec, 0x08, 0xe8, 0x00,\n"
+    "                   0x00, 0x00, 0x00, 0x58, 0x8d, 0x80, 0x16, 0x00,\n"
+    "                   0x00, 0x00, 0x89, 0x04, 0x24, 0xe8, 0xe6, 0xff,\n"
+    "                   0xff, 0xff, 0x31, 0xc0, 0x83, 0xc4, 0x08, 0x5d,\n"
+    "                   0xc3 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x16\n"
+    "       type:       GENERIC_RELOC_VANILLA\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "     - offset:     0x0e\n"
+    "       scattered:  true\n"
+    "       type:       GENERIC_RELOC_LOCAL_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x21\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       GENERIC_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xb\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0021\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 33UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x55);
+  EXPECT_EQ((int)(sect1.content[1]), 0x89);
+  EXPECT_EQ(sect1.relocations.size(), 3UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x16U);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 1U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x0eU);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0x21);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0U);
+  EXPECT_TRUE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::GENERIC_RELOC_PAIR);
+  EXPECT_EQ(reloc3.length, 2);
+  EXPECT_FALSE(reloc3.pcRel);
+  EXPECT_EQ(reloc3.symbol, 0U);
+  EXPECT_EQ((int)(reloc3.value), 0xb);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x021ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_armv6) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv6\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   4\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x80, 0x40, 0x2d, 0xe9, 0x10, 0x00, 0x9f, 0xe5,\n"
+    "                   0x0d, 0x70, 0xa0, 0xe1, 0x00, 0x00, 0x8f, 0xe0,\n"
+    "                   0xfa, 0xff, 0xff, 0xeb, 0x00, 0x00, 0xa0, 0xe3,\n"
+    "                   0x80, 0x80, 0xbd, 0xe8, 0x0c, 0x00, 0x00, 0x00 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x1c\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x20\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "     - offset:     0x10\n"
+    "       type:       ARM_RELOC_BR24\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0020\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 4U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 32UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x80);
+  EXPECT_EQ((int)(sect1.content[1]), 0x40);
+  EXPECT_EQ(sect1.relocations.size(), 3UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x1cU);
+  EXPECT_TRUE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_RELOC_SECTDIFF);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_FALSE(reloc1.pcRel);
+  EXPECT_EQ(reloc1.symbol, 0U);
+  EXPECT_EQ((int)(reloc1.value), 0x20);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x0U);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0xc);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0x10U);
+  EXPECT_FALSE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_BR24);
+  EXPECT_EQ(reloc3.length, 2);
+  EXPECT_TRUE(reloc3.pcRel);
+  EXPECT_TRUE(reloc3.isExtern);
+  EXPECT_EQ(reloc3.symbol, 1U);
+  EXPECT_EQ((int)(reloc3.value), 0);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x020ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_armv7) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7\n"
+    "file-type: MH_OBJECT\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   2\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x80, 0xb5, 0x40, 0xf2, 0x06, 0x00, 0x6f, 0x46,\n"
+    "                   0xc0, 0xf2, 0x00, 0x00, 0x78, 0x44, 0xff, 0xf7,\n"
+    "                   0xf8, 0xef, 0x00, 0x20, 0x80, 0xbd ]\n"
+    "    relocations:\n"
+    "     - offset:     0x0e\n"
+    "       type:       ARM_THUMB_RELOC_BR22\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "     - offset:     0x08\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_HALF_SECTDIFF\n"
+    "       length:     3\n"
+    "       pc-rel:     false\n"
+    "       value:      0x16\n"
+    "     - offset:     0x06\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     3\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "     - offset:     0x02\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_HALF_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x16\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   1\n"
+    "    address:     0x0016\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    desc:   [ N_ARM_THUMB_DEF ]\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes),
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ((uint16_t)sect1.alignment, 2U);
+  EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 22UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x80);
+  EXPECT_EQ((int)(sect1.content[1]), 0xb5);
+  EXPECT_EQ(sect1.relocations.size(), 5UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x0eU);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 1U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x8U);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(reloc2.length, 3);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0x16);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0x6U);
+  EXPECT_TRUE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc3.length, 3);
+  EXPECT_FALSE(reloc3.pcRel);
+  EXPECT_EQ(reloc3.symbol, 0U);
+  EXPECT_EQ((int)(reloc3.value), 0xc);
+   const Relocation& reloc4 = sect1.relocations[3];
+  EXPECT_EQ(reloc4.offset, 0x2U);
+  EXPECT_TRUE(reloc4.scattered);
+  EXPECT_EQ((int)reloc4.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(reloc4.length, 2);
+  EXPECT_FALSE(reloc4.pcRel);
+  EXPECT_EQ(reloc4.symbol, 0U);
+  EXPECT_EQ((int)(reloc4.value), 0x16);
+  const Relocation& reloc5 = sect1.relocations[4];
+  EXPECT_EQ(reloc5.offset, 0x0U);
+  EXPECT_TRUE(reloc5.scattered);
+  EXPECT_EQ((int)reloc5.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc5.length, 2);
+  EXPECT_FALSE(reloc5.pcRel);
+  EXPECT_EQ(reloc5.symbol, 0U);
+  EXPECT_EQ((int)(reloc5.value), 0xc);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ((uint16_t)sect2.alignment, 1U);
+  EXPECT_EQ((uint64_t)sect2.address, 0x016ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), (int)(llvm::MachO::N_ARM_THUMB_DEF));
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
diff --git a/unittests/MachOTests/empty_obj_x86_armv7.txt b/unittests/MachOTests/empty_obj_x86_armv7.txt
new file mode 100644 (file)
index 0000000..9d340cb
--- /dev/null
@@ -0,0 +1,1272 @@
+0xca, 0xfe, 0xba, 0xbe, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00,
+0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x40,
+0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
+0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00,
+0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x98, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xce, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x00, 0x09,
+0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00,
+0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74,
+0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00